Landing the new ComboBox. Note that only gtkcombobox.h and
authorKristian Rietveld <kris@gtk.org>
Fri, 26 Sep 2003 21:57:06 +0000 (21:57 +0000)
committerKristian Rietveld <kristian@src.gnome.org>
Fri, 26 Sep 2003 21:57:06 +0000 (21:57 +0000)
Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>

Landing the new ComboBox. Note that only gtkcombobox.h and
gtkcomboboxentry.h are public.

* gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.

* gtk/Makefile.am, gtk/gtk.h: adding the new files.

* tests/testcombo.c: and a new test.

* tests/Makefile.am: adding the new test.

17 files changed:
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/Makefile.am
gtk/gtk.h
gtk/gtkcellview.c [new file with mode: 0644]
gtk/gtkcellview.h [new file with mode: 0644]
gtk/gtkcellviewmenuitem.c [new file with mode: 0644]
gtk/gtkcellviewmenuitem.h [new file with mode: 0644]
gtk/gtkcombobox.c [new file with mode: 0644]
gtk/gtkcombobox.h [new file with mode: 0644]
gtk/gtkcomboboxentry.c [new file with mode: 0644]
gtk/gtkcomboboxentry.h [new file with mode: 0644]
tests/Makefile.am
tests/testcombo.c [new file with mode: 0644]

index e6acdd0240dd93b496fd4824f2c25ecc281c9aa0..ceb5917d1066a23eca07ad93bcc3b733b2b7d002 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>
+
+       Landing the new ComboBox. Note that only gtkcombobox.h and
+       gtkcomboboxentry.h are public.
+
+       * gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
+       gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.
+
+       * gtk/Makefile.am, gtk/gtk.h: adding the new files.
+
+       * tests/testcombo.c: and a new test.
+
+       * tests/Makefile.am: adding the new test.
+
 2003-09-25  Tor Lillqvist  <tml@iki.fi>
 
        * demos/gtk-demo/main.c: Don't use hardcoded DEMOCODEDIR on Windows.
index e6acdd0240dd93b496fd4824f2c25ecc281c9aa0..ceb5917d1066a23eca07ad93bcc3b733b2b7d002 100644 (file)
@@ -1,3 +1,17 @@
+Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>
+
+       Landing the new ComboBox. Note that only gtkcombobox.h and
+       gtkcomboboxentry.h are public.
+
+       * gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
+       gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.
+
+       * gtk/Makefile.am, gtk/gtk.h: adding the new files.
+
+       * tests/testcombo.c: and a new test.
+
+       * tests/Makefile.am: adding the new test.
+
 2003-09-25  Tor Lillqvist  <tml@iki.fi>
 
        * demos/gtk-demo/main.c: Don't use hardcoded DEMOCODEDIR on Windows.
index e6acdd0240dd93b496fd4824f2c25ecc281c9aa0..ceb5917d1066a23eca07ad93bcc3b733b2b7d002 100644 (file)
@@ -1,3 +1,17 @@
+Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>
+
+       Landing the new ComboBox. Note that only gtkcombobox.h and
+       gtkcomboboxentry.h are public.
+
+       * gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
+       gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.
+
+       * gtk/Makefile.am, gtk/gtk.h: adding the new files.
+
+       * tests/testcombo.c: and a new test.
+
+       * tests/Makefile.am: adding the new test.
+
 2003-09-25  Tor Lillqvist  <tml@iki.fi>
 
        * demos/gtk-demo/main.c: Don't use hardcoded DEMOCODEDIR on Windows.
index e6acdd0240dd93b496fd4824f2c25ecc281c9aa0..ceb5917d1066a23eca07ad93bcc3b733b2b7d002 100644 (file)
@@ -1,3 +1,17 @@
+Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>
+
+       Landing the new ComboBox. Note that only gtkcombobox.h and
+       gtkcomboboxentry.h are public.
+
+       * gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
+       gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.
+
+       * gtk/Makefile.am, gtk/gtk.h: adding the new files.
+
+       * tests/testcombo.c: and a new test.
+
+       * tests/Makefile.am: adding the new test.
+
 2003-09-25  Tor Lillqvist  <tml@iki.fi>
 
        * demos/gtk-demo/main.c: Don't use hardcoded DEMOCODEDIR on Windows.
index e6acdd0240dd93b496fd4824f2c25ecc281c9aa0..ceb5917d1066a23eca07ad93bcc3b733b2b7d002 100644 (file)
@@ -1,3 +1,17 @@
+Fri Sep 26 23:49:44 2003  Kristian Rietveld  <kris@gtk.org>
+
+       Landing the new ComboBox. Note that only gtkcombobox.h and
+       gtkcomboboxentry.h are public.
+
+       * gtk/gtkcellview.[ch], gtk/gtkcellviewmenuitem.[ch],
+       gtk/gtkcombobox.[ch], gtk/gtkcomboboxentry.[ch]: new files.
+
+       * gtk/Makefile.am, gtk/gtk.h: adding the new files.
+
+       * tests/testcombo.c: and a new test.
+
+       * tests/Makefile.am: adding the new test.
+
 2003-09-25  Tor Lillqvist  <tml@iki.fi>
 
        * demos/gtk-demo/main.c: Don't use hardcoded DEMOCODEDIR on Windows.
index c0bcf177e8b36a94becf8c5a17a6de90af6b7fb8..646894e6141aa080a919e26782c4688206d0aacc 100644 (file)
@@ -118,6 +118,8 @@ gtk_public_h_sources =          \
        gtkcolorsel.h           \
        gtkcolorseldialog.h     \
        gtkcombo.h              \
+       gtkcombobox.h           \
+       gtkcomboboxentry.h      \
        gtkcontainer.h          \
        gtkctree.h              \
        gtkcurve.h              \
@@ -249,6 +251,8 @@ gtk_public_h_sources =          \
 
 # GTK+ header files that don't get installed
 gtk_private_h_sources =         \
+       gtkcellview.h           \
+       gtkcellviewmenuitem.h   \
        gtkentryprivate.h       \
        gtkrbtree.h             \
        gtktextbtree.h          \
@@ -290,6 +294,8 @@ gtk_c_sources =                 \
        gtkcellrendererpixbuf.c \
        gtkcellrenderertext.c   \
        gtkcellrenderertoggle.c \
+       gtkcellview.c           \
+       gtkcellviewmenuitem.c   \
        gtkcheckbutton.c        \
        gtkcheckmenuitem.c      \
        gtkclipboard.c          \
@@ -298,6 +304,8 @@ gtk_c_sources =                 \
        gtkcolorsel.c           \
        gtkcolorseldialog.c     \
        gtkcombo.c              \
+       gtkcombobox.c           \
+       gtkcomboboxentry.c      \
        gtkcontainer.c          \
        gtkctree.c              \
        gtkcurve.c              \
index cbb0de3577116e8a9392f183b601ce8c87557081..034040720b7f1a96f47cdacc413c9f6bb556eca1 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -58,6 +58,8 @@
 #include <gtk/gtkcolorsel.h>
 #include <gtk/gtkcolorseldialog.h>
 #include <gtk/gtkcombo.h>
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtkcomboboxentry.h>
 #include <gtk/gtkcontainer.h>
 #include <gtk/gtkctree.h>
 #include <gtk/gtkcurve.h>
diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c
new file mode 100644 (file)
index 0000000..448851f
--- /dev/null
@@ -0,0 +1,835 @@
+/* gtkellview.c
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkcellview.h>
+#include <gtk/gtkintl.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrendererpixbuf.h>
+#include <gobject/gmarshal.h>
+
+typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
+struct _GtkCellViewCellInfo
+{
+  GtkCellRenderer *cell;
+
+  gint requested_width;
+  gint real_width;
+  guint expand : 1;
+  guint pack : 1;
+
+  GSList *attributes;
+};
+
+struct _GtkCellViewPrivate
+{
+  GtkTreeModel *model;
+  GtkTreeRowReference *displayed_row;
+  GList *cell_list;
+  gint spacing;
+
+  GdkColor background;
+  gboolean background_set;
+};
+
+
+static void        gtk_cell_view_class_init               (GtkCellViewClass *klass);
+static void        gtk_cell_view_get_property             (GObject           *object,
+                                                           guint             param_id,
+                                                           GValue           *value,
+                                                           GParamSpec       *pspec);
+static void        gtk_cell_view_set_property             (GObject          *object,
+                                                           guint             param_id,
+                                                           const GValue     *value,
+                                                           GParamSpec       *pspec);
+static void        gtk_cell_view_init                     (GtkCellView      *cellview);
+static void        gtk_cell_view_finalize                 (GObject          *object);
+static void        gtk_cell_view_style_set                (GtkWidget        *widget,
+                                                           GtkStyle         *previous_style);
+static void        gtk_cell_view_size_request             (GtkWidget        *widget,
+                                                           GtkRequisition   *requisition);
+static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
+                                                           GtkAllocation    *allocation);
+static gboolean    gtk_cell_view_expose                   (GtkWidget        *widget,
+                                                           GdkEventExpose   *event);
+static void        gtk_cell_view_set_attributesv          (GtkCellView      *cellview,
+                                                           GtkCellRenderer  *renderer,
+                                                           va_list           args);
+static void        gtk_cell_view_set_valuesv              (GtkCellView      *cellview,
+                                                           GtkCellRenderer  *renderer,
+                                                           va_list           args);
+static void        gtk_cell_view_set_cell_data            (GtkCellView      *cellview);
+
+
+enum
+{
+  PROP_0,
+  PROP_BACKGROUND,
+  PROP_BACKGROUND_GDK,
+  PROP_BACKGROUND_SET
+};
+
+static GtkObjectClass *parent_class = NULL;
+
+
+GType
+gtk_cell_view_get_type (void)
+{
+  static GType cell_view_type = 0;
+
+  if (!cell_view_type)
+    {
+      static const GTypeInfo cell_view_info =
+        {
+          sizeof (GtkCellViewClass),
+          NULL, /* base_init */
+          NULL, /* base_finalize */
+          (GClassInitFunc) gtk_cell_view_class_init,
+          NULL, /* class_finalize */
+          NULL, /* class_data */
+          sizeof (GtkCellView),
+          0,
+          (GInstanceInitFunc) gtk_cell_view_init
+        };
+
+      cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView",
+                                               &cell_view_info, 0);
+    }
+
+  return cell_view_type;
+}
+
+static void
+gtk_cell_view_class_init (GtkCellViewClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->get_property = gtk_cell_view_get_property;
+  gobject_class->set_property = gtk_cell_view_set_property;
+  gobject_class->finalize = gtk_cell_view_finalize;
+
+  widget_class->expose_event = gtk_cell_view_expose;
+  widget_class->size_allocate = gtk_cell_view_size_allocate;
+  widget_class->size_request = gtk_cell_view_size_request;
+  widget_class->style_set = gtk_cell_view_style_set;
+
+  /* properties */
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND,
+                                   g_param_spec_string ("background",
+                                                        _("Background color name"),
+                                                        _("Background color as a string"),
+                                                        NULL,
+                                                        G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_GDK,
+                                   g_param_spec_boxed ("background_gdk",
+                                                      _("Background color"),
+                                                      _("Background color as a GdkColor"),
+                                                      GDK_TYPE_COLOR,
+                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
+
+  ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
+                _("Background set"),
+                _("Whether this tag affects the background color"));
+
+  g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
+}
+
+static void
+gtk_cell_view_get_property (GObject    *object,
+                            guint       param_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GtkCellView *view = GTK_CELL_VIEW (object);
+
+  switch (param_id)
+    {
+      case PROP_BACKGROUND_GDK:
+        {
+          GdkColor color;
+
+          color = view->priv->background;
+
+          g_value_set_boxed (value, &color);
+        }
+        break;
+      case PROP_BACKGROUND_SET:
+        g_value_set_boolean (value, view->priv->background_set);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+gtk_cell_view_set_property (GObject      *object,
+                            guint         param_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GtkCellView *view = GTK_CELL_VIEW (object);
+
+  switch (param_id)
+    {
+      case PROP_BACKGROUND:
+        {
+          GdkColor color;
+
+          if (!g_value_get_string (value))
+            gtk_cell_view_set_background_color (view, NULL);
+          else if (gdk_color_parse (g_value_get_string (value), &color))
+            gtk_cell_view_set_background_color (view, &color);
+          else
+            g_warning ("Don't know color `%s'", g_value_get_string (value));
+
+          g_object_notify (object, "background_gdk");
+        }
+        break;
+      case PROP_BACKGROUND_GDK:
+        gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
+        break;
+      case PROP_BACKGROUND_SET:
+        view->priv->background_set = g_value_get_boolean (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+gtk_cell_view_init (GtkCellView *cellview)
+{
+  GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
+
+  cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
+}
+
+static void
+gtk_cell_view_style_set (GtkWidget *widget,
+                         GtkStyle  *previous_style)
+{
+  if (previous_style && GTK_WIDGET_REALIZED (widget))
+    gdk_window_set_background (widget->window,
+                               &widget->style->base[GTK_WIDGET_STATE (widget)]);
+}
+
+static void
+gtk_cell_view_finalize (GObject *object)
+{
+  GtkCellView *cellview = GTK_CELL_VIEW (object);
+
+  if (cellview->priv->cell_list)
+    {
+      g_list_foreach (cellview->priv->cell_list, (GFunc)g_free, NULL);
+      g_list_free (cellview->priv->cell_list);
+    }
+  cellview->priv->cell_list = NULL;
+
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+gtk_cell_view_size_request (GtkWidget      *widget,
+                            GtkRequisition *requisition)
+{
+  GList *i;
+  gboolean first_cell = TRUE;
+  GtkCellView *cellview;
+
+  cellview = GTK_CELL_VIEW (widget);
+
+  requisition->width = 0;
+  requisition->height = 0;
+
+  if (cellview->priv->displayed_row)
+    gtk_cell_view_set_cell_data (cellview);
+
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      gint width, height;
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (!info->cell->visible)
+        continue;
+
+      if (!first_cell)
+        requisition->width += cellview->priv->spacing;
+
+      gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
+                                  &width, &height);
+
+      info->requested_width = width;
+      requisition->width += width;
+      requisition->height = MAX (requisition->height, height);
+
+      first_cell = FALSE;
+    }
+}
+
+static void
+gtk_cell_view_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+  GList *i;
+  gint expand_cell_count = 0;
+  gint full_requested_width = 0;
+  gint extra_space;
+  GtkCellView *cellview;
+
+  widget->allocation = *allocation;
+
+  cellview = GTK_CELL_VIEW (widget);
+
+  /* checking how much extra space we have */
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (!info->cell->visible)
+        continue;
+
+      if (info->expand)
+        expand_cell_count++;
+
+      full_requested_width += info->requested_width;
+    }
+
+  extra_space = widget->allocation.width - full_requested_width;
+  if (extra_space < 0)
+    extra_space = 0;
+  else if (extra_space > 0 && expand_cell_count > 0)
+    extra_space /= expand_cell_count;
+
+  /* iterate list for PACK_START cells */
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (info->pack == GTK_PACK_END)
+        continue;
+
+      if (!info->cell->visible)
+        continue;
+
+      info->real_width = info->requested_width + (info->expand?extra_space:0);
+    }
+
+  /* iterate list for PACK_END cells */
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (info->pack == GTK_PACK_START)
+        continue;
+
+      if (!info->cell->visible)
+        continue;
+
+      info->real_width = info->requested_width + (info->expand?extra_space:0);
+    }
+}
+
+static gboolean
+gtk_cell_view_expose (GtkWidget      *widget,
+                      GdkEventExpose *event)
+{
+  GList *i;
+  GtkCellView *cellview;
+  GdkRectangle area;
+
+  cellview = GTK_CELL_VIEW (widget);
+
+  if (! GTK_WIDGET_DRAWABLE (widget))
+    return FALSE;
+
+  /* "blank" background */
+  if (cellview->priv->background_set)
+    {
+      GdkGC *gc;
+
+      gc = gdk_gc_new (GTK_WIDGET (cellview)->window);
+      gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background);
+
+      gdk_draw_rectangle (GTK_WIDGET (cellview)->window,
+                          gc,
+                          TRUE,
+
+                          /*0, 0,*/
+                          widget->allocation.x,
+                          widget->allocation.y,
+
+                          widget->allocation.width,
+                          widget->allocation.height);
+
+      g_object_unref (G_OBJECT (gc));
+    }
+
+  /* set cell data (if applicable) */
+  if (cellview->priv->displayed_row)
+    gtk_cell_view_set_cell_data (cellview);
+
+  /* render cells */
+  area = widget->allocation;
+
+  /* we draw on our very own window, initialize x and y to zero */
+  area.x = widget->allocation.x;
+  area.y = widget->allocation.y;
+
+  /* PACK_START */
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (info->pack == GTK_PACK_END)
+        continue;
+
+      if (!info->cell->visible)
+        continue;
+
+      area.width = info->real_width;
+
+      gtk_cell_renderer_render (info->cell,
+                                event->window,
+                                widget,
+                                /* FIXME! */
+                                &area, &area, &event->area, 0);
+
+      area.x += info->real_width;
+    }
+
+  /* PACK_END */
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (info->pack == GTK_PACK_START)
+        continue;
+
+      if (!info->cell->visible)
+        continue;
+
+      area.width = info->real_width;
+
+      gtk_cell_renderer_render (info->cell,
+                                widget->window,
+                                widget,
+                                /* FIXME ! */
+                                &area, &area, &event->area, 0);
+      area.x += info->real_width;
+    }
+
+  return FALSE;
+}
+
+GtkWidget *
+gtk_cell_view_new (void)
+{
+  GtkCellView *cellview;
+
+  cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL));
+
+  return GTK_WIDGET (cellview);
+}
+
+GtkWidget *
+gtk_cell_view_new_with_text (const gchar *text)
+{
+  GtkCellView *cellview;
+  GtkCellRenderer *renderer;
+  GValue value = {0, };
+
+  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_view_pack_start (cellview, renderer, TRUE);
+
+  g_value_init (&value, G_TYPE_STRING);
+  g_value_set_string (&value, text);
+  gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL);
+  g_value_unset (&value);
+
+  return GTK_WIDGET (cellview);
+}
+
+GtkWidget *
+gtk_cell_view_new_with_markup (const gchar *markup)
+{
+  GtkCellView *cellview;
+  GtkCellRenderer *renderer;
+  GValue value = {0, };
+
+  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_view_pack_start (cellview, renderer, TRUE);
+
+  g_value_init (&value, G_TYPE_STRING);
+  g_value_set_string (&value, markup);
+  gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL);
+  g_value_unset (&value);
+
+  return GTK_WIDGET (cellview);
+}
+
+GtkWidget *
+gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
+{
+  GtkCellView *cellview;
+  GtkCellRenderer *renderer;
+  GValue value = {0, };
+
+  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
+
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_cell_view_pack_start (cellview, renderer, TRUE);
+
+  g_value_init (&value, GDK_TYPE_PIXBUF);
+  g_value_set_object (&value, pixbuf);
+  gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL);
+  g_value_unset (&value);
+
+  return GTK_WIDGET (cellview);
+}
+
+static GtkCellViewCellInfo *
+gtk_cell_view_get_cell_info (GtkCellView     *cellview,
+                             GtkCellRenderer *renderer)
+{
+  GList *i;
+
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      if (info->cell == renderer)
+        return info;
+    }
+
+  return NULL;
+}
+
+void
+gtk_cell_view_pack_start (GtkCellView     *cellview,
+                          GtkCellRenderer *renderer,
+                          gboolean         expand)
+{
+  GtkCellViewCellInfo *info;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+  g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
+
+  g_object_ref (G_OBJECT (renderer));
+  gtk_object_sink (GTK_OBJECT (renderer));
+
+  info = g_new0 (GtkCellViewCellInfo, 1);
+  info->cell = renderer;
+  info->expand = expand ? TRUE : FALSE;
+  info->pack = GTK_PACK_START;
+
+  cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
+}
+
+void
+gtk_cell_view_pack_end (GtkCellView     *cellview,
+                        GtkCellRenderer *renderer,
+                        gboolean         expand)
+{
+  GtkCellViewCellInfo *info;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+  g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
+
+  g_object_ref (G_OBJECT (renderer));
+  gtk_object_sink (GTK_OBJECT (renderer));
+
+  info = g_new0 (GtkCellViewCellInfo, 1);
+  info->cell = renderer;
+  info->expand = expand ? TRUE : FALSE;
+  info->pack = GTK_PACK_END;
+
+  cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
+}
+
+void
+gtk_cell_view_add_attribute (GtkCellView     *cellview,
+                             GtkCellRenderer *renderer,
+                             const gchar     *attribute,
+                             gint             column)
+{
+  GtkCellViewCellInfo *info;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  info = gtk_cell_view_get_cell_info (cellview, renderer);
+  g_return_if_fail (info != NULL);
+
+  info->attributes = g_slist_prepend (info->attributes,
+                                      GINT_TO_POINTER (column));
+  info->attributes = g_slist_prepend (info->attributes,
+                                      g_strdup (attribute));
+}
+
+void
+gtk_cell_view_clear (GtkCellView *cellview)
+{
+  GList *i;
+
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+
+      gtk_cell_view_clear_attributes (cellview, info->cell);
+      g_object_unref (G_OBJECT (info->cell));
+      g_free (info);
+    }
+
+  g_list_free (cellview->priv->cell_list);
+  cellview->priv->cell_list = NULL;
+}
+
+void
+gtk_cell_view_clear_attributes (GtkCellView     *cellview,
+                                GtkCellRenderer *renderer)
+{
+  GtkCellViewCellInfo *info;
+  GSList *list;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+
+  info = gtk_cell_view_get_cell_info (cellview, renderer);
+
+  list = info->attributes;
+
+  while (list && list->next)
+    {
+      g_free (list->data);
+      list = list->next->next;
+    }
+  g_slist_free (list);
+
+  info->attributes = NULL;
+}
+
+static void
+gtk_cell_view_set_attributesv (GtkCellView     *cellview,
+                               GtkCellRenderer *renderer,
+                               va_list          args)
+{
+  gchar *attribute;
+  gint column;
+
+  attribute = va_arg (args, gchar *);
+
+  gtk_cell_view_clear_attributes (cellview, renderer);
+
+  while (attribute)
+    {
+      column = va_arg (args, gint);
+      gtk_cell_view_add_attribute (cellview, renderer, attribute, column);
+      attribute = va_arg (args, gchar *);
+    }
+}
+
+void
+gtk_cell_view_set_attributes (GtkCellView     *cellview,
+                              GtkCellRenderer *renderer,
+                              ...)
+{
+  va_list args;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+  g_return_if_fail (gtk_cell_view_get_cell_info (cellview, renderer));
+
+  va_start (args, renderer);
+  gtk_cell_view_set_attributesv (cellview, renderer, args);
+  va_end (args);
+}
+
+void
+gtk_cell_view_set_value (GtkCellView     *cellview,
+                         GtkCellRenderer *renderer,
+                         gchar           *property,
+                         GValue          *value)
+{
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+
+  g_object_set_property (G_OBJECT (renderer), property, value);
+
+  /* force redraw */
+  gtk_widget_queue_draw (GTK_WIDGET (cellview));
+}
+
+static void
+gtk_cell_view_set_valuesv (GtkCellView     *cellview,
+                           GtkCellRenderer *renderer,
+                           va_list          args)
+{
+  gchar *attribute;
+  GValue *value;
+
+  attribute = va_arg (args, gchar *);
+
+  while (attribute)
+    {
+      value = va_arg (args, GValue *);
+      gtk_cell_view_set_value (cellview, renderer, attribute, value);
+      attribute = va_arg (args, gchar *);
+    }
+}
+
+void
+gtk_cell_view_set_values (GtkCellView     *cellview,
+                          GtkCellRenderer *renderer,
+                          ...)
+{
+  va_list args;
+
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+  g_return_if_fail (gtk_cell_view_get_cell_info (cellview, renderer));
+
+  va_start (args, renderer);
+  gtk_cell_view_set_valuesv (cellview, renderer, args);
+  va_end (args);
+}
+
+void
+gtk_cell_view_set_model (GtkCellView  *cellview,
+                         GtkTreeModel *model)
+{
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_TREE_MODEL (model));
+
+  if (cellview->priv->model)
+    {
+      if (cellview->priv->displayed_row)
+        gtk_tree_row_reference_free (cellview->priv->displayed_row);
+      cellview->priv->displayed_row = NULL;
+
+      g_object_unref (G_OBJECT (cellview->priv->model));
+      cellview->priv->model = NULL;
+    }
+
+  cellview->priv->model = model;
+
+  if (cellview->priv->model)
+    g_object_ref (G_OBJECT (cellview->priv->model));
+}
+
+static void
+gtk_cell_view_set_cell_data (GtkCellView *cellview)
+{
+  GList *i;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  g_return_if_fail (cellview->priv->displayed_row != NULL);
+
+  path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
+  gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
+  gtk_tree_path_free (path);
+
+  for (i = cellview->priv->cell_list; i; i = i->next)
+    {
+      GSList *j;
+      GtkCellViewCellInfo *info = i->data;
+
+      for (j = info->attributes; j && j->next; j = j->next->next)
+        {
+          gchar *property = j->data;
+          gint column = GPOINTER_TO_INT (j->next->data);
+          GValue value = {0, };
+
+          gtk_tree_model_get_value (cellview->priv->model, &iter,
+                                    column, &value);
+          g_object_set_property (G_OBJECT (info->cell),
+                                 property, &value);
+          g_value_unset (&value);
+        }
+    }
+}
+
+void
+gtk_cell_view_set_displayed_row (GtkCellView *cellview,
+                                 GtkTreePath *path)
+{
+  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
+  g_return_if_fail (GTK_IS_TREE_MODEL (cellview->priv->model));
+  g_return_if_fail (path != NULL);
+
+  if (cellview->priv->displayed_row)
+    gtk_tree_row_reference_free (cellview->priv->displayed_row);
+
+  cellview->priv->displayed_row =
+    gtk_tree_row_reference_new (cellview->priv->model, path);
+
+  /* force redraw */
+  gtk_widget_queue_draw (GTK_WIDGET (cellview));
+}
+
+GtkTreePath *
+gtk_cell_view_get_displayed_row (GtkCellView *cellview)
+{
+  g_return_val_if_fail (GTK_IS_CELL_VIEW (cellview), NULL);
+
+  if (!cellview->priv->displayed_row)
+    return NULL;
+
+  return gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
+}
+
+void
+gtk_cell_view_set_background_color (GtkCellView *view,
+                                    GdkColor    *color)
+{
+  g_return_if_fail (GTK_IS_CELL_VIEW (view));
+
+  if (color)
+    {
+      if (!view->priv->background_set)
+        {
+          view->priv->background_set = TRUE;
+          g_object_notify (G_OBJECT (view), "background_set");
+        }
+
+      view->priv->background = *color;
+    }
+  else
+    {
+      if (view->priv->background_set)
+        {
+          view->priv->background_set = FALSE;
+          g_object_notify (G_OBJECT (view), "background_set");
+        }
+    }
+}
diff --git a/gtk/gtkcellview.h b/gtk/gtkcellview.h
new file mode 100644 (file)
index 0000000..523e921
--- /dev/null
@@ -0,0 +1,96 @@
+/* gtkcellview.h
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_CELL_VIEW_H__
+#define __GTK_CELL_VIEW_H__
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkcellrenderer.h>
+#include <gtk/gtktreemodel.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CELL_VIEW                (gtk_cell_view_get_type ())
+#define GTK_CELL_VIEW(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW, GtkCellView))
+#define GTK_CELL_VIEW_CLASS(vtable)       (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_CELL_VIEW, GtkCellViewClass))
+#define GTK_IS_CELL_VIEW(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW))
+#define GTK_IS_CELL_VIEW_CLASS(vtable)    (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_CELL_VIEW))
+#define GTK_CELL_VIEW_GET_CLASS(inst)     (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_CELL_VIEW, GtkCellViewClass))
+#define GTK_CELL_VIEW_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
+
+typedef struct _GtkCellView             GtkCellView;
+typedef struct _GtkCellViewClass        GtkCellViewClass;
+typedef struct _GtkCellViewPrivate      GtkCellViewPrivate;
+
+struct _GtkCellView
+{
+  GtkWidget parent_instance;
+
+  /*< private >*/
+  GtkCellViewPrivate *priv;
+};
+
+struct _GtkCellViewClass
+{
+  GtkWidgetClass parent_class;
+};
+
+GType             gtk_cell_view_get_type               (void);
+GtkWidget        *gtk_cell_view_new                    (void);
+GtkWidget        *gtk_cell_view_new_with_text          (const gchar     *text);
+GtkWidget        *gtk_cell_view_new_with_markup        (const gchar     *markup);
+GtkWidget        *gtk_cell_view_new_with_pixbuf        (GdkPixbuf       *pixbuf);
+
+
+void              gtk_cell_view_pack_start              (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         gboolean         expand);
+void              gtk_cell_view_pack_end                (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         gboolean         expand);
+void              gtk_cell_view_clear                   (GtkCellView     *cell_view);
+void              gtk_cell_view_add_attribute           (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         const gchar     *attribute,
+                                                         gint             column);
+void              gtk_cell_view_clear_attributes        (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *attribute);
+void              gtk_cell_view_set_attributes          (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         ...);
+void              gtk_cell_view_set_value               (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         gchar           *property,
+                                                         GValue          *value);
+void              gtk_cell_view_set_values              (GtkCellView     *cell_view,
+                                                         GtkCellRenderer *renderer,
+                                                         ...);
+
+void              gtk_cell_view_set_model               (GtkCellView     *cell_view,
+                                                         GtkTreeModel    *model);
+void              gtk_cell_view_set_displayed_row       (GtkCellView     *cell_view,
+                                                         GtkTreePath     *path);
+GtkTreePath      *gtk_cell_view_get_displayed_row       (GtkCellView     *cell_view);
+
+void              gtk_cell_view_set_background_color    (GtkCellView     *cell_view,
+                                                         GdkColor        *color);
+
+G_END_DECLS
+
+#endif /* __GTK_CELL_VIEW_H__ */
diff --git a/gtk/gtkcellviewmenuitem.c b/gtk/gtkcellviewmenuitem.c
new file mode 100644 (file)
index 0000000..d69435f
--- /dev/null
@@ -0,0 +1,146 @@
+/* gtkcellviewmenuitem.c
+ * Copyright (C) 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkcellviewmenuitem.h>
+#include <gtk/gtkcellview.h>
+
+struct _GtkCellViewMenuItemPrivate
+{
+  GtkWidget *cell_view;
+};
+
+static void gtk_cell_view_menu_item_init       (GtkCellViewMenuItem      *item);
+static void gtk_cell_view_menu_item_class_init (GtkCellViewMenuItemClass *klass);
+
+
+GType
+gtk_cell_view_menu_item_get_type (void)
+{
+  static GType cell_view_menu_item_type = 0;
+
+  if (!cell_view_menu_item_type)
+    {
+      static const GTypeInfo cell_view_menu_item_info =
+        {
+          sizeof (GtkCellViewMenuItemClass),
+          NULL,
+          NULL,
+          (GClassInitFunc) gtk_cell_view_menu_item_class_init,
+          NULL,
+          NULL,
+          sizeof (GtkCellViewMenuItem),
+          0,
+          (GInstanceInitFunc) gtk_cell_view_menu_item_init
+        };
+
+      cell_view_menu_item_type =
+        g_type_register_static (GTK_TYPE_MENU_ITEM, "GtkCellViewMenuItem",
+                                &cell_view_menu_item_info, 0);
+    }
+
+  return cell_view_menu_item_type;
+}
+
+static void
+gtk_cell_view_menu_item_class_init (GtkCellViewMenuItemClass *klass)
+{
+  g_type_class_add_private ((GObjectClass *)klass,
+                            sizeof (GtkCellViewMenuItemPrivate));
+}
+
+static void
+gtk_cell_view_menu_item_init (GtkCellViewMenuItem *item)
+{
+  item->priv = GTK_CELL_VIEW_MENU_ITEM_GET_PRIVATE (item);
+}
+
+GtkWidget *
+gtk_cell_view_menu_item_new (void)
+{
+  GtkCellViewMenuItem *item;
+
+  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
+
+  item->priv->cell_view = gtk_cell_view_new ();
+  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
+  gtk_widget_show (item->priv->cell_view);
+
+  return GTK_WIDGET (item);
+}
+
+GtkWidget *
+gtk_cell_view_menu_item_new_with_pixbuf (GdkPixbuf *pixbuf)
+{
+  GtkCellViewMenuItem *item;
+
+  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
+
+  item->priv->cell_view = gtk_cell_view_new_with_pixbuf (pixbuf);
+  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
+  gtk_widget_show (item->priv->cell_view);
+
+  return GTK_WIDGET (item);
+}
+
+GtkWidget *
+gtk_cell_view_menu_item_new_with_text (const gchar *text)
+{
+  GtkCellViewMenuItem *item;
+
+  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
+
+  item->priv->cell_view = gtk_cell_view_new_with_text (text);
+  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
+  gtk_widget_show (item->priv->cell_view);
+
+  return GTK_WIDGET (item);
+}
+
+GtkWidget *
+gtk_cell_view_menu_item_new_with_markup (const gchar *markup)
+{
+  GtkCellViewMenuItem *item;
+
+  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
+
+  item->priv->cell_view = gtk_cell_view_new_with_markup (markup);
+  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
+  gtk_widget_show (item->priv->cell_view);
+
+  return GTK_WIDGET (item);
+}
+
+GtkWidget *
+gtk_cell_view_menu_item_new_from_model (GtkTreeModel *model,
+                                        GtkTreePath  *path)
+{
+  GtkCellViewMenuItem *item;
+
+  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
+
+  item->priv->cell_view = gtk_cell_view_new ();
+  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
+
+  gtk_cell_view_set_model (GTK_CELL_VIEW (item->priv->cell_view), model);
+  gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (item->priv->cell_view), path);
+
+  gtk_widget_show (item->priv->cell_view);
+
+  return GTK_WIDGET (item);
+}
diff --git a/gtk/gtkcellviewmenuitem.h b/gtk/gtkcellviewmenuitem.h
new file mode 100644 (file)
index 0000000..539fabc
--- /dev/null
@@ -0,0 +1,68 @@
+/* gtkcellviewmenuitem.h
+ * Copyright (C) 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_CELL_VIEW_MENU_ITEM_H__
+#define __GTK_CELL_VIEW_MENU_ITEM_H__
+
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtktreemodel.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CELL_VIEW_MENU_ITEM              (gtk_cell_view_menu_item_get_type ())
+#define GTK_CELL_VIEW_MENU_ITEM(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItem))
+#define GTK_CELL_VIEW_MENU_ITEM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItemClass))
+#define GTK_IS_CELL_VIEW_MENU_ITEM(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM))
+#define GTK_IS_CELL_VIEW_MENU_ITEM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_VIEW_MENU_ITEM))
+#define GTK_CELL_VIEW_MENU_ITEM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItemClass))
+#define GTK_CELL_VIEW_MENU_ITEM_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItemPrivate))
+
+
+typedef struct _GtkCellViewMenuItem        GtkCellViewMenuItem;
+typedef struct _GtkCellViewMenuItemClass   GtkCellViewMenuItemClass;
+typedef struct _GtkCellViewMenuItemPrivate GtkCellViewMenuItemPrivate;
+
+struct _GtkCellViewMenuItem
+{
+  GtkMenuItem parent_instance;
+
+  /*< private >*/
+  GtkCellViewMenuItemPrivate *priv;
+};
+
+struct _GtkCellViewMenuItemClass
+{
+  GtkMenuItemClass parent_class;
+};
+
+
+GType      gtk_cell_view_menu_item_get_type        (void);
+GtkWidget *gtk_cell_view_menu_item_new             (void);
+
+GtkWidget *gtk_cell_view_menu_item_new_with_pixbuf (GdkPixbuf   *pixbuf);
+GtkWidget *gtk_cell_view_menu_item_new_with_text   (const gchar *text);
+GtkWidget *gtk_cell_view_menu_item_new_with_markup (const gchar *markup);
+
+GtkWidget *gtk_cell_view_menu_item_new_from_model  (GtkTreeModel *model,
+                                                    GtkTreePath  *path);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CELL_VIEW_MENU_ITEM_H__ */
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
new file mode 100644 (file)
index 0000000..9bbf551
--- /dev/null
@@ -0,0 +1,2271 @@
+/* gtkcombobox.c
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtkcellview.h>
+#include <gtk/gtkcellviewmenuitem.h>
+
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkvseparator.h>
+#include <gtk/gtkarrow.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkeventbox.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkbindings.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkwindow.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+#include <stdarg.h>
+
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+
+
+/* WELCOME, to THE house of evil code */
+
+
+typedef struct _ComboCellInfo ComboCellInfo;
+struct _ComboCellInfo
+{
+  GtkCellRenderer *cell;
+  GSList *attributes;
+
+  guint expand : 1;
+  guint pack : 1;
+};
+
+struct _GtkComboBoxPrivate
+{
+  GtkTreeModel *model;
+
+  gint col_column;
+  gint row_column;
+
+  gint wrap_width;
+
+  gint active_item;
+
+  GtkWidget *tree_view;
+  GtkTreeViewColumn *column;
+
+  GtkWidget *cell_view;
+  GtkWidget *measurer;
+
+  GtkWidget *hbox;
+  GtkWidget *cell_view_frame;
+
+  GtkWidget *button;
+  GtkWidget *arrow;
+  GtkWidget *separator;
+
+  GtkWidget *popup_widget;
+  GtkWidget *popup_window;
+  GtkWidget *popup_frame;
+
+  guint inserted_id;
+  guint deleted_id;
+
+  gint width;
+  GSList *cells;
+
+  guint changed_id;
+
+  guint popup_in_progress : 1;
+};
+
+enum {
+  CHANGED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_MODEL,
+  PROP_WRAP_WIDTH,
+  PROP_ROW_SPAN_COLUMN,
+  PROP_COLUMN_SPAN_COLUMN,
+  PROP_ACTIVE
+};
+
+static GtkBinClass *parent_class = NULL;
+static guint combo_box_signals[LAST_SIGNAL] = {0,};
+
+#define BONUS_PADDING 4
+
+
+/* common */
+static void     gtk_combo_box_class_init           (GtkComboBoxClass *klass);
+static void     gtk_combo_box_init                 (GtkComboBox      *combo_box);
+
+static void     gtk_combo_box_set_property         (GObject         *object,
+                                                    guint            prop_id,
+                                                    const GValue    *value,
+                                                    GParamSpec      *spec);
+static void     gtk_combo_box_get_property         (GObject         *object,
+                                                    guint            prop_id,
+                                                    GValue          *value,
+                                                    GParamSpec      *spec);
+
+static void     gtk_combo_box_set_model            (GtkComboBox     *combo_box,
+                                                    GtkTreeModel    *model);
+
+static void     gtk_combo_box_style_set            (GtkWidget       *widget,
+                                                    GtkStyle        *previous_style,
+                                                    gpointer         data);
+static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
+                                                    gpointer         data);
+static void     gtk_combo_box_add                  (GtkContainer    *container,
+                                                    GtkWidget       *widget);
+
+static ComboCellInfo *gtk_combo_box_get_cell_info  (GtkComboBox      *combo_box,
+                                                    GtkCellRenderer  *cell);
+
+static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
+                                                    gpointer          user_data);
+
+static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
+                                                    GtkWidget        *popup);
+static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
+                                                    gint             *x,
+                                                    gint             *y,
+                                                    gint             *push_in,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_popup                (GtkComboBox      *combo_box);
+static void     gtk_combo_box_popdown              (GtkComboBox      *combo_box);
+
+static gint     gtk_combo_box_calc_requested_width (GtkComboBox      *combo_box,
+                                                    GtkTreePath      *path);
+static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box);
+
+static void     gtk_combo_box_size_request         (GtkWidget        *widget,
+                                                    GtkRequisition   *requisition);
+static void     gtk_combo_box_size_allocate        (GtkWidget        *widget,
+                                                    GtkAllocation    *allocation);
+static void     gtk_combo_box_forall               (GtkContainer     *container,
+                                                    gboolean          include_internals,
+                                                    GtkCallback       callback,
+                                                    gpointer          callback_data);
+static gboolean gtk_combo_box_expose_event         (GtkWidget        *widget,
+                                                    GdkEventExpose   *event);
+
+/* list */
+static void     gtk_combo_box_list_setup           (GtkComboBox      *combo_box);
+static void     gtk_combo_box_list_destroy         (GtkComboBox      *combo_box);
+
+static gboolean gtk_combo_box_list_button_released (GtkWidget        *widget,
+                                                    GdkEventButton   *event,
+                                                    gpointer          data);
+static gboolean gtk_combo_box_list_key_press       (GtkWidget        *widget,
+                                                    GdkEventKey      *event,
+                                                    gpointer          data);
+static gboolean gtk_combo_box_list_button_pressed  (GtkWidget        *widget,
+                                                    GdkEventButton   *event,
+                                                    gpointer          data);
+
+static void     gtk_combo_box_list_row_changed     (GtkTreeModel     *model,
+                                                    GtkTreePath      *path,
+                                                    GtkTreeIter      *iter,
+                                                    gpointer          data);
+
+/* menu */
+static void     gtk_combo_box_menu_setup           (GtkComboBox      *combo_box,
+                                                    gboolean          add_childs);
+static void     gtk_combo_box_menu_destroy         (GtkComboBox      *combo_box);
+
+static void     gtk_combo_box_item_get_size        (GtkComboBox      *combo_box,
+                                                    gint              index,
+                                                    gint             *cols,
+                                                    gint             *rows);
+static void     gtk_combo_box_relayout_item        (GtkComboBox      *combo_box,
+                                                    gint              index);
+static void     gtk_combo_box_relayout             (GtkComboBox      *combo_box);
+
+static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
+                                                    GdkEventButton   *event,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
+                                                    GtkTreePath      *path,
+                                                    GtkTreeIter      *iter,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
+                                                    GtkTreePath      *path,
+                                                    gpointer          user_data);
+static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
+                                                    GtkTreePath      *path,
+                                                    GtkTreeIter      *iter,
+                                                    gpointer          data);
+
+
+GType
+gtk_combo_box_get_type (void)
+{
+  static GType combo_box_type = 0;
+
+  if (!combo_box_type)
+    {
+      static const GTypeInfo combo_box_info =
+        {
+          sizeof (GtkComboBoxClass),
+          NULL, /* base_init */
+          NULL, /* base_finalize */
+          (GClassInitFunc) gtk_combo_box_class_init,
+          NULL, /* class_finalize */
+          NULL, /* class_data */
+          sizeof (GtkComboBox),
+          0,
+          (GInstanceInitFunc) gtk_combo_box_init
+        };
+
+      combo_box_type = g_type_register_static (GTK_TYPE_BIN,
+                                               "GtkComboBox",
+                                               &combo_box_info,
+                                               0);
+    }
+
+  return combo_box_type;
+}
+
+/* common */
+static void
+gtk_combo_box_class_init (GtkComboBoxClass *klass)
+{
+  GObjectClass *object_class;
+  GtkBindingSet *binding_set;
+  GtkContainerClass *container_class;
+  GtkWidgetClass *widget_class;
+
+  binding_set = gtk_binding_set_by_class (klass);
+
+  container_class = (GtkContainerClass *)klass;
+  container_class->forall = gtk_combo_box_forall;
+  container_class->add = gtk_combo_box_add;
+
+  widget_class = (GtkWidgetClass *)klass;
+  widget_class->size_allocate = gtk_combo_box_size_allocate;
+  widget_class->size_request = gtk_combo_box_size_request;
+  widget_class->expose_event = gtk_combo_box_expose_event;
+
+  object_class = (GObjectClass *)klass;
+  object_class->set_property = gtk_combo_box_set_property;
+  object_class->get_property = gtk_combo_box_get_property;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  /* signals */
+  combo_box_signals[CHANGED] =
+    g_signal_new ("changed",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkComboBoxClass, changed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  /* properties */
+  g_object_class_install_property (object_class,
+                                   PROP_MODEL,
+                                   g_param_spec_object ("model",
+                                                        _("ComboBox model"),
+                                                        _("The model for the combo box"),
+                                                        GTK_TYPE_TREE_MODEL,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_WRAP_WIDTH,
+                                   g_param_spec_int ("wrap_width",
+                                                     _("Wrap width"),
+                                                     _("Wrap width for layouting the items in a grid"),
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_ROW_SPAN_COLUMN,
+                                   g_param_spec_int ("row_span_column",
+                                                     _("Row span column"),
+                                                     _("TreeModel column containing the row span values"),
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_COLUMN_SPAN_COLUMN,
+                                   g_param_spec_int ("column_span_column",
+                                                     _("Column span column"),
+                                                     _("TreeModel column containing the column span values"),
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_ACTIVE,
+                                   g_param_spec_int ("active",
+                                                     _("Active item"),
+                                                     _("The item which is currently active"),
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_boolean ("appearance",
+                                                                 _("ComboBox appareance"),
+                                                                 _("ComboBox appearance, where TRUE means Windows-style."),
+                                                                 FALSE,
+                                                                 G_PARAM_READWRITE));
+
+  g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
+}
+
+static void
+gtk_combo_box_init (GtkComboBox *combo_box)
+{
+  combo_box->priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
+
+  g_signal_connect (combo_box, "style_set",
+                    G_CALLBACK (gtk_combo_box_style_set), NULL);
+
+  combo_box->priv->cell_view = gtk_cell_view_new ();
+  gtk_container_add (GTK_CONTAINER (combo_box), combo_box->priv->cell_view);
+
+  combo_box->priv->measurer = gtk_cell_view_new ();
+
+  combo_box->priv->width = 0;
+  combo_box->priv->wrap_width = 0;
+
+  combo_box->priv->active_item = -1;
+  combo_box->priv->col_column = -1;
+  combo_box->priv->row_column = -1;
+}
+
+static void
+gtk_combo_box_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+
+  switch (prop_id)
+    {
+      case PROP_MODEL:
+        gtk_combo_box_set_model (combo_box, g_value_get_object (value));
+        break;
+
+      case PROP_WRAP_WIDTH:
+        gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
+        break;
+
+      case PROP_ROW_SPAN_COLUMN:
+        gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
+        break;
+
+      case PROP_COLUMN_SPAN_COLUMN:
+        gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
+        break;
+
+      case PROP_ACTIVE:
+        gtk_combo_box_set_active (combo_box, g_value_get_int (value));
+        break;
+
+      default:
+        break;
+    }
+}
+
+static void
+gtk_combo_box_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+
+  switch (prop_id)
+    {
+      case PROP_MODEL:
+        g_value_set_object (value, combo_box->priv->model);
+        break;
+
+      case PROP_WRAP_WIDTH:
+        g_value_set_int (value, combo_box->priv->wrap_width);
+        break;
+
+      case PROP_ROW_SPAN_COLUMN:
+        g_value_set_int (value, combo_box->priv->row_column);
+        break;
+
+      case PROP_COLUMN_SPAN_COLUMN:
+        g_value_set_int (value, combo_box->priv->col_column);
+        break;
+
+      case PROP_ACTIVE:
+        g_value_set_int (value, gtk_combo_box_get_active (combo_box));
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gtk_combo_box_set_model (GtkComboBox  *combo_box,
+                         GtkTreeModel *model)
+{
+  if (combo_box->priv->model)
+    return;
+
+  combo_box->priv->model = model;
+  g_object_ref (G_OBJECT (combo_box->priv->model));
+  gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
+                           combo_box->priv->model);
+  gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->measurer),
+                           combo_box->priv->model);
+}
+
+static void
+gtk_combo_box_style_set (GtkWidget *widget,
+                         GtkStyle  *previous_style,
+                         gpointer   data)
+{
+  gboolean appearance;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+  /* if wrap_width > 0, then we are in grid-mode and forced to use
+   * unix style
+   */
+  if (combo_box->priv->wrap_width)
+    return;
+
+  gtk_widget_style_get (widget,
+                        "appearance", &appearance,
+                        NULL);
+
+  /* TRUE is windows style */
+  if (appearance)
+    {
+      if (GTK_IS_MENU (combo_box->priv->popup_widget))
+        gtk_combo_box_menu_destroy (combo_box);
+      gtk_combo_box_list_setup (combo_box);
+    }
+  else
+    {
+      if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
+        gtk_combo_box_list_destroy (combo_box);
+      gtk_combo_box_menu_setup (combo_box, TRUE);
+    }
+}
+
+static void
+gtk_combo_box_button_toggled (GtkWidget *widget,
+                              gpointer   data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+    {
+      if (!combo_box->priv->popup_in_progress)
+        gtk_combo_box_popup (combo_box);
+    }
+  else
+    gtk_combo_box_popdown (combo_box);
+}
+
+static void
+gtk_combo_box_add (GtkContainer *container,
+                   GtkWidget    *widget)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
+
+  if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
+    {
+      gtk_container_remove (container, combo_box->priv->cell_view);
+      (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
+    }
+  else
+    {
+      (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
+    }
+
+  if (combo_box->priv->cell_view &&
+      widget != combo_box->priv->cell_view)
+    {
+      /* since the cell_view was unparented, it's gone now */
+      combo_box->priv->cell_view = NULL;
+
+      if (!combo_box->priv->tree_view && combo_box->priv->separator)
+        {
+          gtk_widget_unparent (combo_box->priv->separator);
+
+          g_object_ref (G_OBJECT (combo_box->priv->arrow));
+          gtk_widget_unparent (combo_box->priv->arrow);
+          gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
+                             combo_box->priv->arrow);
+          g_object_unref (G_OBJECT (combo_box->priv->arrow));
+
+          gtk_widget_queue_resize (GTK_WIDGET (container));
+        }
+      else if (combo_box->priv->cell_view_frame)
+        {
+          gtk_widget_unparent (combo_box->priv->cell_view_frame);
+          combo_box->priv->cell_view_frame = NULL;
+        }
+    }
+}
+
+static ComboCellInfo *
+gtk_combo_box_get_cell_info (GtkComboBox     *combo_box,
+                             GtkCellRenderer *cell)
+{
+  GSList *i;
+
+  for (i = combo_box->priv->cells; i; i = i->next)
+    {
+      ComboCellInfo *info = (ComboCellInfo *)i->data;
+
+      if (info->cell == cell)
+        return info;
+    }
+
+  return NULL;
+}
+
+static void
+gtk_combo_box_menu_show (GtkWidget *menu,
+                         gpointer   user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
+                                TRUE);
+}
+
+static void
+gtk_combo_box_menu_hide (GtkWidget *menu,
+                         gpointer   user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
+                                FALSE);
+}
+
+static void
+gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
+                                GtkWidget   *popup)
+{
+  if (GTK_IS_MENU (combo_box->priv->popup_widget))
+    combo_box->priv->popup_widget = NULL;
+  else if (combo_box->priv->popup_widget)
+    {
+      gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
+                            combo_box->priv->popup_widget);
+      g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
+      combo_box->priv->popup_widget = NULL;
+    }
+
+  if (GTK_IS_MENU (popup))
+    {
+      if (combo_box->priv->popup_window)
+        {
+          gtk_widget_destroy (combo_box->priv->popup_window);
+          combo_box->priv->popup_window = combo_box->priv->popup_frame = NULL;
+        }
+
+      combo_box->priv->popup_widget = popup;
+
+      g_signal_connect (popup, "show",
+                        G_CALLBACK (gtk_combo_box_menu_show), combo_box);
+      g_signal_connect (popup, "hide",
+                        G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
+
+      /* FIXME: need to attach to widget? */
+    }
+  else
+    {
+      if (!combo_box->priv->popup_window)
+        {
+          combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+          combo_box->priv->popup_frame = gtk_frame_new (NULL);
+          gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
+                                     GTK_SHADOW_NONE);
+          gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
+                             combo_box->priv->popup_frame);
+          gtk_widget_show (combo_box->priv->popup_frame);
+        }
+
+      gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
+                         popup);
+      gtk_widget_show (popup);
+      g_object_ref (G_OBJECT (popup));
+      combo_box->priv->popup_widget = popup;
+    }
+}
+
+static void
+gtk_combo_box_menu_position (GtkMenu  *menu,
+                             gint     *x,
+                             gint     *y,
+                             gint     *push_in,
+                             gpointer  user_data)
+{
+  gint sx, sy;
+  GtkWidget *child;
+  GtkRequisition req;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  /* FIXME: is using the size request here broken? */
+  child = GTK_BIN (combo_box)->child;
+
+  gdk_window_get_origin (child->window, &sx, &sy);
+
+  gtk_widget_size_request (GTK_WIDGET (menu), &req);
+
+  *x = sx + child->allocation.width - req.width;
+  *y = sy + child->allocation.height;
+
+  if (GTK_WIDGET_NO_WINDOW (child))
+    {
+      *x += child->allocation.x;
+      *y += child->allocation.y;
+    }
+
+  *push_in = TRUE;
+}
+
+static void
+gtk_combo_box_popup (GtkComboBox *combo_box)
+{
+  gint x, y, width, height;
+  GtkWidget *sample;
+
+  if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
+    return;
+
+  if (GTK_IS_MENU (combo_box->priv->popup_widget))
+    {
+      if (combo_box->priv->active_item != -1)
+        {
+          GList *childs;
+
+          childs = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget));
+          gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
+                                      g_list_nth_data (childs, combo_box->priv->active_item));
+          g_list_free (childs);
+        }
+
+      gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
+                      NULL, NULL,
+                      gtk_combo_box_menu_position, combo_box,
+                      0, 0);
+      return;
+    }
+
+  /* size it */
+  sample = GTK_BIN (combo_box)->child;
+
+  width = sample->allocation.width;
+  height = sample->allocation.height;
+
+  gdk_window_get_origin (sample->window,
+                         &x, &y);
+  gtk_widget_set_size_request (combo_box->priv->popup_window,
+                               width, -1);
+
+  if (GTK_WIDGET_NO_WINDOW (sample))
+    {
+      x += sample->allocation.x;
+      y += sample->allocation.y;
+    }
+
+  gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window),
+                   x, y + height);
+
+  /* popup */
+  gtk_widget_show_all (combo_box->priv->popup_window);
+
+  gtk_widget_grab_focus (combo_box->priv->popup_window);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
+                                TRUE);
+
+  if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
+    {
+      gdk_keyboard_grab (combo_box->priv->popup_window->window,
+                         FALSE, GDK_CURRENT_TIME);
+      gtk_widget_grab_focus (combo_box->priv->tree_view);
+    }
+}
+
+static void
+gtk_combo_box_popdown (GtkComboBox *combo_box)
+{
+  if (GTK_IS_MENU (combo_box->priv->popup_widget))
+    {
+      gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
+      return;
+    }
+
+  gtk_widget_hide_all (combo_box->priv->popup_window);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
+                                FALSE);
+}
+
+static gint
+gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
+                                    GtkTreePath *path)
+{
+  gint padding;
+  GtkRequisition req;
+
+  gtk_widget_style_get (combo_box->priv->measurer,
+                        "focus-line-width", &padding,
+                        NULL);
+
+  /* add some pixels for good measure */
+  padding += BONUS_PADDING;
+
+  gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->measurer),
+                                   path);
+
+  /* nasty trick to get around the sizegroup's size request caching */
+  (* GTK_WIDGET_GET_CLASS (combo_box->priv->measurer)->size_request) (combo_box->priv->measurer, &req);
+
+  return req.width + padding;
+}
+
+static void
+gtk_combo_box_remeasure (GtkComboBox *combo_box)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  gint padding = 0;
+
+  if (!gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
+    return;
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+
+  gtk_widget_style_get (combo_box->priv->measurer,
+                        "focus-line-width", &padding,
+                        NULL);
+
+  /* add some pixels for good measure */
+  padding += BONUS_PADDING;
+
+  do
+    {
+      GtkRequisition req;
+
+      gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->measurer),
+                                       path);
+
+      /* nasty trick to get around the sizegroup's size request caching */
+      (* GTK_WIDGET_GET_CLASS (combo_box->priv->measurer)->size_request) (combo_box->priv->measurer, &req);
+
+      combo_box->priv->width = MAX (combo_box->priv->width,
+                                    req.width + padding);
+
+      gtk_tree_path_next (path);
+    }
+  while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
+
+  gtk_tree_path_free (path);
+
+  if (combo_box->priv->cell_view)
+    {
+      gtk_widget_set_size_request (combo_box->priv->cell_view,
+                                   combo_box->priv->width, -1);
+      gtk_widget_queue_resize (combo_box->priv->cell_view);
+    }
+}
+
+static void
+gtk_combo_box_size_request (GtkWidget      *widget,
+                            GtkRequisition *requisition)
+{
+  gint width, height;
+  GtkRequisition bin_req;
+
+  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+  /* common */
+  gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
+
+  if (!combo_box->priv->tree_view)
+    {
+      /* menu mode */
+
+      if (combo_box->priv->cell_view)
+        {
+          GtkRequisition sep_req, arrow_req;
+          gint border_width, xthickness, ythickness;
+
+          border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
+          xthickness = combo_box->priv->button->style->xthickness;
+          ythickness = combo_box->priv->button->style->ythickness;
+
+          bin_req.width = MAX (bin_req.width, combo_box->priv->width);
+
+          /* separator */
+          gtk_widget_set_size_request (combo_box->priv->separator,
+                                       -1, bin_req.height);
+          gtk_widget_size_request (combo_box->priv->separator, &sep_req);
+
+          /* arrow */
+          gtk_widget_set_size_request (combo_box->priv->arrow,
+                                       -1, bin_req.height);
+          gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
+
+          height = MAX (sep_req.height, arrow_req.height);
+          height = MAX (height, bin_req.height);
+
+          width = bin_req.width + sep_req.width + arrow_req.width;
+
+          height += border_width + 1 + xthickness * 2 + 4;
+          width += border_width + 1 + ythickness * 2 + 4;
+
+          gtk_widget_set_size_request (combo_box->priv->button, width, height);
+          gtk_widget_size_request (combo_box->priv->button, requisition);
+        }
+      else
+        {
+          GtkRequisition but_req;
+
+          gtk_widget_set_size_request (combo_box->priv->button,
+                                       -1, bin_req.height);
+          gtk_widget_size_request (combo_box->priv->button, &but_req);
+
+          requisition->width = bin_req.width + but_req.width;
+          requisition->height = MAX (bin_req.height, but_req.height);
+        }
+    }
+  else
+    {
+      /* list mode */
+      GtkRequisition button_req;
+
+      /* sample + frame */
+      *requisition = bin_req;
+
+      if (combo_box->priv->cell_view_frame)
+        {
+          requisition->width +=
+            (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness) * 2;
+          requisition->height +=
+            (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness) * 2;
+        }
+
+      /* the button */
+      gtk_widget_set_size_request (combo_box->priv->button,
+                                   -1, requisition->height);
+      gtk_widget_size_request (combo_box->priv->button, &button_req);
+
+      requisition->height = MAX (requisition->height, button_req.height);
+      requisition->width += button_req.width;
+    }
+}
+
+static void
+gtk_combo_box_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+  GtkAllocation child;
+  GtkRequisition req;
+
+  widget->allocation = *allocation;
+
+  if (!combo_box->priv->tree_view)
+    {
+      if (combo_box->priv->cell_view)
+        {
+          gint border_width, xthickness, ythickness;
+          gint width;
+
+          /* menu mode */
+          gtk_widget_size_allocate (combo_box->priv->button, allocation);
+
+          /* set some things ready */
+          border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
+          xthickness = combo_box->priv->button->style->xthickness;
+          ythickness = combo_box->priv->button->style->ythickness;
+
+          child.x = allocation->x + border_width + 1 + xthickness + 2;
+          child.y = allocation->y + border_width + 1 + ythickness + 2;
+
+          width = allocation->width - (border_width + 1 + ythickness * 2 + 4);
+
+          /* handle the childs */
+          gtk_widget_size_request (combo_box->priv->arrow, &req);
+          child.width = req.width;
+          child.height = req.height;
+          child.x += width - req.width;
+          gtk_widget_size_allocate (combo_box->priv->arrow, &child);
+
+          gtk_widget_size_request (combo_box->priv->separator, &req);
+          child.width = req.width;
+          child.height = req.height;
+          child.x -= req.width;
+          gtk_widget_size_allocate (combo_box->priv->separator, &child);
+
+          child.width = child.x;
+          child.x = allocation->x + border_width + 1 + xthickness + 2;
+          child.width -= child.x;
+
+          gtk_widget_size_request (GTK_BIN (widget)->child, &req);
+          child.height = req.height;
+          gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
+        }
+      else
+        {
+          gtk_widget_size_request (combo_box->priv->button, &req);
+          child.x = allocation->x + allocation->width - req.width;
+          child.y = allocation->y;
+          child.width = req.width;
+          child.height = req.height;
+          gtk_widget_size_allocate (combo_box->priv->button, &child);
+
+          child.x = allocation->x;
+          child.y = allocation->y;
+          child.width = allocation->width - req.width;
+          gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
+        }
+    }
+  else
+    {
+      /* list mode */
+
+      /* button */
+      gtk_widget_size_request (combo_box->priv->button, &req);
+      child.x = allocation->x + allocation->width - req.width;
+      child.y = allocation->y;
+      child.width = req.width;
+      child.height = req.height;
+      gtk_widget_size_allocate (combo_box->priv->button, &child);
+
+      /* frame */
+      child.x = allocation->x;
+      child.y = allocation->y;
+      child.width = allocation->width - req.width;
+
+      if (combo_box->priv->cell_view_frame)
+        {
+          gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
+
+          /* the sample */
+          child.x +=
+            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
+          child.y +=
+            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
+          child.width -=
+            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
+          child.height -=
+            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
+            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
+        }
+
+      gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
+    }
+}
+
+static void
+gtk_combo_box_forall (GtkContainer *container,
+                      gboolean      include_internals,
+                      GtkCallback   callback,
+                      gpointer      callback_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
+
+  if (include_internals)
+    {
+      if (!combo_box->priv->tree_view)
+        {
+          if (combo_box->priv->cell_view && combo_box->priv->button)
+            {
+              (* callback) (combo_box->priv->button, callback_data);
+              (* callback) (combo_box->priv->separator, callback_data);
+              (* callback) (combo_box->priv->arrow, callback_data);
+            }
+          else if (combo_box->priv->arrow)
+            {
+              (* callback) (combo_box->priv->button, callback_data);
+              (* callback) (combo_box->priv->arrow, callback_data);
+            }
+        }
+      else
+        {
+          (* callback) (combo_box->priv->button, callback_data);
+          if (combo_box->priv->cell_view_frame)
+            (* callback) (combo_box->priv->cell_view_frame, callback_data);
+        }
+    }
+
+  if (GTK_BIN (container)->child)
+    (* callback) (GTK_BIN (container)->child, callback_data);
+}
+
+static gboolean
+gtk_combo_box_expose_event (GtkWidget      *widget,
+                            GdkEventExpose *event)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+
+  if (!combo_box->priv->tree_view)
+    {
+      gtk_container_propagate_expose (GTK_CONTAINER (widget),
+                                      combo_box->priv->button, event);
+
+      if (combo_box->priv->separator)
+        {
+          gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
+                                          combo_box->priv->separator, event);
+
+          /* if not in this case, arrow gets its expose event from button */
+          gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
+                                          combo_box->priv->arrow, event);
+        }
+    }
+  else
+    {
+      gtk_container_propagate_expose (GTK_CONTAINER (widget),
+                                      combo_box->priv->button, event);
+
+      if (combo_box->priv->cell_view_frame)
+        gtk_container_propagate_expose (GTK_CONTAINER (widget),
+                                        combo_box->priv->cell_view_frame, event);
+    }
+
+  gtk_container_propagate_expose (GTK_CONTAINER (widget),
+                                  GTK_BIN (widget)->child, event);
+
+  return FALSE;
+}
+
+/*
+ * menu style
+ */
+
+static void
+cell_view_sync_cells (GtkComboBox *combo_box,
+                      GtkCellView *cell_view)
+{
+  GSList *k;
+
+  for (k = combo_box->priv->cells; k; k = k->next)
+    {
+      GSList *j;
+      ComboCellInfo *info = (ComboCellInfo *)k->data;
+
+      if (info->pack == GTK_PACK_START)
+        gtk_cell_view_pack_start (cell_view,
+                                  info->cell, info->expand);
+      else if (info->pack == GTK_PACK_END)
+        gtk_cell_view_pack_end (cell_view,
+                                info->cell, info->expand);
+
+      for (j = info->attributes; j; j = j->next->next)
+        {
+          gtk_cell_view_add_attribute (cell_view,
+                                       info->cell,
+                                       j->data,
+                                       GPOINTER_TO_INT (j->next->data));
+        }
+    }
+}
+
+static void
+gtk_combo_box_menu_setup (GtkComboBox *combo_box,
+                          gboolean     add_childs)
+{
+  gint i, items;
+  GtkWidget *box;
+  GtkWidget *tmp;
+
+  if (combo_box->priv->cell_view)
+    {
+      combo_box->priv->button = gtk_toggle_button_new ();
+      g_signal_connect (combo_box->priv->button, "toggled",
+                        G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
+      gtk_widget_set_parent (combo_box->priv->button,
+                             GTK_BIN (combo_box)->child->parent);
+
+      combo_box->priv->separator = gtk_vseparator_new ();
+      gtk_widget_set_parent (combo_box->priv->separator,
+                             combo_box->priv->button);
+      gtk_widget_show (combo_box->priv->separator);
+
+      combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+      gtk_widget_set_parent (combo_box->priv->arrow, combo_box->priv->button);
+      gtk_widget_show (combo_box->priv->arrow);
+
+      gtk_widget_show_all (combo_box->priv->button);
+
+      if (GTK_WIDGET_MAPPED (GTK_BIN (combo_box)->child))
+        {
+          /* I have no clue why, but we need to manually map in this case. */
+          gtk_widget_map (combo_box->priv->separator);
+          gtk_widget_map (combo_box->priv->arrow);
+        }
+    }
+  else
+    {
+      combo_box->priv->button = gtk_toggle_button_new ();
+      g_signal_connect (combo_box->priv->button, "toggled",
+                        G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
+      gtk_widget_set_parent (combo_box->priv->button,
+                             GTK_BIN (combo_box)->child->parent);
+
+      combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+      gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
+                         combo_box->priv->arrow);
+      gtk_widget_show_all (combo_box->priv->button);
+    }
+
+  combo_box->priv->inserted_id =
+    g_signal_connect (combo_box->priv->model, "row_inserted",
+                      G_CALLBACK (gtk_combo_box_menu_row_inserted),
+                      combo_box);
+  combo_box->priv->deleted_id =
+    g_signal_connect (combo_box->priv->model, "row_deleted",
+                      G_CALLBACK (gtk_combo_box_menu_row_deleted),
+                      combo_box);
+  combo_box->priv->changed_id =
+    g_signal_connect (combo_box->priv->model, "row_changed",
+                      G_CALLBACK (gtk_combo_box_menu_row_changed),
+                      combo_box);
+
+  g_signal_connect (combo_box->priv->button, "button_press_event",
+                    G_CALLBACK (gtk_combo_box_menu_button_press),
+                    combo_box);
+
+  /* create our funky menu */
+  box = gtk_menu_new ();
+  gtk_combo_box_set_popup_widget (combo_box, box);
+
+  /* add items */
+  if (!add_childs)
+    return;
+
+  items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
+
+  for (i = 0; i < items; i++)
+    {
+      GtkTreePath *path;
+
+      path = gtk_tree_path_new_from_indices (i, -1);
+      tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
+                                                    path);
+      g_signal_connect (tmp, "activate",
+                        G_CALLBACK (gtk_combo_box_menu_item_activate),
+                        combo_box);
+
+      cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
+
+      gtk_menu_shell_append (GTK_MENU_SHELL (box), tmp);
+      gtk_widget_show (tmp);
+
+      gtk_tree_path_free (path);
+    }
+}
+
+static void
+gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
+{
+  /* disconnect signal handlers */
+  g_signal_handler_disconnect (combo_box->priv->model,
+                               combo_box->priv->inserted_id);
+  g_signal_handler_disconnect (combo_box->priv->model,
+                               combo_box->priv->deleted_id);
+  g_signal_handler_disconnect (combo_box->priv->model,
+                               combo_box->priv->changed_id);
+
+  g_signal_handlers_disconnect_matched (combo_box->priv->button,
+                                        G_SIGNAL_MATCH_DATA,
+                                        0, 0, NULL,
+                                        gtk_combo_box_menu_button_press, NULL);
+
+  combo_box->priv->inserted_id =
+  combo_box->priv->deleted_id =
+  combo_box->priv->changed_id = -1;
+
+  /* unparent will remove our latest ref */
+  if (combo_box->priv->cell_view)
+    {
+      gtk_widget_unparent (combo_box->priv->arrow);
+      gtk_widget_unparent (combo_box->priv->separator);
+      gtk_widget_unparent (combo_box->priv->button);
+    }
+  else
+    {
+      /* will destroy the arrow too */
+      gtk_widget_unparent (combo_box->priv->button);
+    }
+
+  /* changing the popup window will unref the menu and the childs */
+}
+
+/*
+ * grid
+ */
+
+static void
+gtk_combo_box_item_get_size (GtkComboBox *combo_box,
+                             gint         index,
+                             gint        *cols,
+                             gint        *rows)
+{
+  GtkTreeIter iter;
+
+  gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index);
+
+  if (cols)
+    {
+      if (combo_box->priv->col_column == -1)
+        *cols = 1;
+      else
+        gtk_tree_model_get (combo_box->priv->model, &iter,
+                            combo_box->priv->col_column, cols,
+                            -1);
+    }
+
+  if (rows)
+    {
+      if (combo_box->priv->row_column == -1)
+        *rows = 1;
+      else
+        gtk_tree_model_get (combo_box->priv->model, &iter,
+                            combo_box->priv->row_column, rows,
+                            -1);
+    }
+}
+
+static gboolean
+menu_occupied (GtkMenu *menu,
+               guint    left_attach,
+               guint    right_attach,
+               guint    top_attach,
+               guint    bottom_attach)
+{
+  GList *i;
+
+  g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
+  g_return_val_if_fail (left_attach < right_attach, TRUE);
+  g_return_val_if_fail (top_attach < bottom_attach, TRUE);
+
+  for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
+    {
+      guint l, r, b, t;
+      gboolean h_intersect = FALSE;
+      gboolean v_intersect = FALSE;
+
+      gtk_container_child_get (GTK_CONTAINER (menu), i->data,
+                               "left_attach", &l,
+                               "right_attach", &r,
+                               "bottom_attach", &b,
+                               "top_attach", &t,
+                               NULL);
+
+      /* look if this item intersects with the given coordinates */
+      h_intersect  = left_attach <= l && l <= right_attach;
+      h_intersect &= left_attach <= r && r <= right_attach;
+
+      v_intersect  = top_attach <= t && t <= bottom_attach;
+      v_intersect &= top_attach <= b && b <= bottom_attach;
+
+      if (h_intersect && v_intersect)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_combo_box_relayout_item (GtkComboBox *combo_box,
+                             gint         index)
+{
+  gint current_col = 0, current_row = 0;
+  gint rows, cols;
+  GList *list;
+  GtkWidget *item;
+  GtkWidget *menu;
+
+  menu = combo_box->priv->popup_widget;
+  if (!GTK_IS_MENU_SHELL (menu))
+    return;
+
+  list = gtk_container_get_children (GTK_CONTAINER (menu));
+  item = g_list_nth_data (list, index);
+
+  gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
+
+  /* look for a good spot */
+  while (1)
+    {
+      if (current_col + cols > combo_box->priv->wrap_width)
+        {
+          current_col = 0;
+          current_row++;
+        }
+
+      if (!menu_occupied (GTK_MENU (menu),
+                          current_col, current_col + cols,
+                          current_row, current_row + rows))
+        break;
+
+      current_col++;
+    }
+
+  /* set attach props */
+  gtk_menu_attach (GTK_MENU (menu), item,
+                   current_col, current_col + cols,
+                   current_row, current_row + rows);
+}
+
+static void
+gtk_combo_box_relayout (GtkComboBox *combo_box)
+{
+  gint i, items;
+  GList *list, *j;
+  GtkWidget *menu;
+
+  /* ensure we are in menu style */
+  if (combo_box->priv->tree_view)
+    gtk_combo_box_list_destroy (combo_box);
+
+  menu = combo_box->priv->popup_widget;
+
+  if (!GTK_IS_MENU_SHELL (menu))
+    {
+      gtk_combo_box_menu_setup (combo_box, FALSE);
+      menu = combo_box->priv->popup_widget;
+    }
+
+  /* get rid of all children */
+  g_return_if_fail (GTK_IS_MENU_SHELL (menu));
+
+  list = gtk_container_get_children (GTK_CONTAINER (menu));
+
+  for (j = g_list_last (list); j; j = j->prev)
+    gtk_container_remove (GTK_CONTAINER (menu), j->data);
+
+  g_list_free (j);
+
+  /* and relayout */
+  items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
+
+  for (i = 0; i < items; i++)
+    {
+      GtkWidget *tmp;
+      GtkTreePath *path;
+
+      path = gtk_tree_path_new_from_indices (i, -1);
+      tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
+                                                    path);
+
+      g_signal_connect (tmp, "activate",
+                        G_CALLBACK (gtk_combo_box_menu_item_activate),
+                        combo_box);
+
+      cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
+
+      gtk_menu_shell_insert (GTK_MENU_SHELL (menu), tmp, i);
+
+      if (combo_box->priv->wrap_width)
+        gtk_combo_box_relayout_item (combo_box, i);
+
+      gtk_widget_show (tmp);
+
+      gtk_tree_path_free (path);
+    }
+}
+
+/* callbacks */
+static gboolean
+gtk_combo_box_menu_button_press (GtkWidget      *widget,
+                                 GdkEventButton *event,
+                                 gpointer        user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  if (! GTK_IS_MENU (combo_box->priv->popup_widget))
+    return FALSE;
+
+  if (event->type == GDK_BUTTON_PRESS && event->button == 1)
+    {
+      gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
+                      NULL, NULL,
+                      gtk_combo_box_menu_position, combo_box,
+                      event->button, event->time);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_combo_box_menu_item_activate (GtkWidget *item,
+                                  gpointer   user_data)
+{
+  gint index;
+  GtkWidget *menu;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  menu = combo_box->priv->popup_widget;
+  g_return_if_fail (GTK_IS_MENU (menu));
+
+  index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
+
+  gtk_combo_box_set_active (combo_box, index);
+}
+
+static void
+gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
+                                 GtkTreePath  *path,
+                                 GtkTreeIter  *iter,
+                                 gpointer      user_data)
+{
+  GtkWidget *menu;
+  GtkWidget *item;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  menu = combo_box->priv->popup_widget;
+  g_return_if_fail (GTK_IS_MENU (menu));
+
+  item = gtk_cell_view_menu_item_new_from_model (model, path);
+  g_signal_connect (item, "activate",
+                    G_CALLBACK (gtk_combo_box_menu_item_activate),
+                    combo_box);
+
+  cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
+
+  gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
+                         gtk_tree_path_get_indices (path)[0]);
+  gtk_widget_show (item);
+}
+
+static void
+gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
+                                GtkTreePath  *path,
+                                gpointer      user_data)
+{
+  gint index, items;
+  GtkWidget *menu;
+  GtkWidget *item;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  index = gtk_tree_path_get_indices (path)[0];
+  items = gtk_tree_model_iter_n_children (model, NULL);
+
+  if (gtk_combo_box_get_active (combo_box) == index)
+    gtk_combo_box_set_active (combo_box, index + 1 % items);
+
+  menu = combo_box->priv->popup_widget;
+  g_return_if_fail (GTK_IS_MENU (menu));
+
+  item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
+  g_return_if_fail (GTK_IS_MENU_ITEM (item));
+
+  gtk_container_remove (GTK_CONTAINER (menu), item);
+}
+
+static void
+gtk_combo_box_menu_row_changed (GtkTreeModel *model,
+                                GtkTreePath  *path,
+                                GtkTreeIter  *iter,
+                                gpointer      user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  gint width;
+
+  if (combo_box->priv->wrap_width)
+    gtk_combo_box_relayout_item (combo_box,
+                                 gtk_tree_path_get_indices (path)[0]);
+
+  width = gtk_combo_box_calc_requested_width (combo_box, path);
+
+  if (width > combo_box->priv->width)
+    {
+      gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
+      gtk_widget_queue_resize (combo_box->priv->cell_view);
+      combo_box->priv->width = width;
+    }
+}
+
+/*
+ * list style
+ */
+
+static void
+gtk_combo_box_list_setup (GtkComboBox *combo_box)
+{
+  GSList *i;
+  GtkTreeSelection *sel;
+
+  combo_box->priv->button = gtk_toggle_button_new ();
+  gtk_widget_set_parent (combo_box->priv->button,
+                         GTK_BIN (combo_box)->child->parent);
+  g_signal_connect (combo_box->priv->button, "button_press_event",
+                    G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
+  g_signal_connect (combo_box->priv->button, "toggled",
+                    G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
+
+  combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+  gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
+                     combo_box->priv->arrow);
+  gtk_widget_show_all (combo_box->priv->button);
+
+  if (combo_box->priv->cell_view)
+    {
+      combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
+      gtk_widget_set_parent (combo_box->priv->cell_view_frame,
+                             GTK_BIN (combo_box)->child->parent);
+      gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
+                                 GTK_SHADOW_IN);
+
+      g_object_set (G_OBJECT (combo_box->priv->cell_view),
+                    "background", "white",
+                    "background_set", TRUE,
+                    NULL);
+
+      gtk_widget_show (combo_box->priv->cell_view_frame);
+    }
+
+  combo_box->priv->tree_view = gtk_tree_view_new ();
+  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
+  gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
+                                     FALSE);
+
+  g_signal_connect (combo_box->priv->tree_view, "button_press_event",
+                    G_CALLBACK (gtk_combo_box_list_button_pressed),
+                    combo_box);
+  g_signal_connect (combo_box->priv->tree_view, "button_release_event",
+                    G_CALLBACK (gtk_combo_box_list_button_released),
+                    combo_box);
+  g_signal_connect (combo_box->priv->tree_view, "key_press_event",
+                    G_CALLBACK (gtk_combo_box_list_key_press),
+                    combo_box);
+
+  combo_box->priv->column = gtk_tree_view_column_new ();
+  gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
+                               combo_box->priv->column);
+
+  /* set the models */
+  gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
+                           combo_box->priv->model);
+
+  combo_box->priv->changed_id =
+    g_signal_connect (combo_box->priv->model, "row_changed",
+                      G_CALLBACK (gtk_combo_box_list_row_changed),
+                      combo_box);
+
+  /* sync up */
+  for (i = combo_box->priv->cells; i; i = i->next)
+    {
+      GSList *j;
+      ComboCellInfo *info = (ComboCellInfo *)i->data;
+
+      if (info->pack == GTK_PACK_START)
+        gtk_tree_view_column_pack_start (combo_box->priv->column,
+                                         info->cell, info->expand);
+      else if (info->pack == GTK_PACK_END)
+        gtk_tree_view_column_pack_end (combo_box->priv->column,
+                                       info->cell, info->expand);
+
+      for (j = info->attributes; j; j = j->next->next)
+        {
+          gtk_tree_view_column_add_attribute (combo_box->priv->column,
+                                              info->cell,
+                                              j->data,
+                                              GPOINTER_TO_INT (j->next->data));
+        }
+    }
+
+  if (combo_box->priv->active_item != -1)
+    {
+      GtkTreePath *path;
+
+      path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
+      if (path)
+        {
+          gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
+                                    path, NULL, FALSE);
+          gtk_tree_path_free (path);
+        }
+    }
+
+  /* set sample/popup widgets */
+  gtk_combo_box_set_popup_widget (GTK_COMBO_BOX (combo_box),
+                                  combo_box->priv->tree_view);
+
+  gtk_widget_show (combo_box->priv->tree_view);
+}
+
+static void
+gtk_combo_box_list_destroy (GtkComboBox *combo_box)
+{
+  /* disconnect signals */
+  g_signal_handler_disconnect (combo_box->priv->model,
+                               combo_box->priv->changed_id);
+  combo_box->priv->changed_id = -1;
+
+  g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
+                                        G_SIGNAL_MATCH_DATA,
+                                        0, 0, NULL, NULL, combo_box);
+  g_signal_handlers_disconnect_matched (combo_box->priv->button,
+                                        G_SIGNAL_MATCH_DATA,
+                                        0, 0, NULL,
+                                        gtk_combo_box_list_button_pressed,
+                                        NULL);
+
+  /* destroy things (unparent will kill the latest ref from us)
+   * last unref on button will destroy the arrow
+   */
+  gtk_widget_unparent (combo_box->priv->button);
+
+  if (combo_box->priv->cell_view)
+    {
+      g_object_set (G_OBJECT (combo_box->priv->cell_view),
+                    "background_set", FALSE,
+                    NULL);
+
+      gtk_widget_unparent (combo_box->priv->cell_view_frame);
+    }
+
+  gtk_widget_destroy (combo_box->priv->tree_view);
+  combo_box->priv->tree_view = NULL;
+  combo_box->priv->popup_widget = NULL;
+}
+
+/* callbacks */
+static void
+gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
+{
+  if (GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
+    gtk_grab_remove (combo_box->priv->tree_view);
+
+  if (GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
+    {
+      gtk_grab_remove (combo_box->priv->popup_window);
+      gdk_pointer_ungrab (GDK_CURRENT_TIME);
+    }
+}
+
+static gboolean
+gtk_combo_box_list_button_pressed (GtkWidget      *widget,
+                                   GdkEventButton *event,
+                                   gpointer        data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+
+  GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
+
+  if (ewidget == combo_box->priv->tree_view)
+    return TRUE;
+
+  if ((ewidget != combo_box->priv->button) ||
+      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
+    return FALSE;
+
+  gtk_combo_box_popup (combo_box);
+
+  gtk_grab_add (combo_box->priv->popup_window);
+  gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
+                    GDK_BUTTON_PRESS_MASK |
+                    GDK_BUTTON_RELEASE_MASK |
+                    GDK_POINTER_MOTION_MASK,
+                    NULL, NULL, GDK_CURRENT_TIME);
+
+  gtk_grab_add (combo_box->priv->tree_view);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
+                                TRUE);
+
+  combo_box->priv->popup_in_progress = TRUE;
+
+  return TRUE;
+}
+
+static gboolean
+gtk_combo_box_list_button_released (GtkWidget      *widget,
+                                    GdkEventButton *event,
+                                    gpointer        data)
+{
+  gboolean ret;
+  GtkTreePath *path = NULL;
+
+  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+
+  gboolean popup_in_progress = FALSE;
+
+  GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
+
+  if (combo_box->priv->popup_in_progress)
+    {
+      popup_in_progress = TRUE;
+      combo_box->priv->popup_in_progress = FALSE;
+    }
+
+  if (ewidget != combo_box->priv->tree_view)
+    {
+      if (ewidget == combo_box->priv->button &&
+          !popup_in_progress &&
+          gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
+        {
+          gtk_combo_box_list_remove_grabs (combo_box);
+          gtk_combo_box_popdown (combo_box);
+          return TRUE;
+        }
+
+      /* released outside treeview */
+      if (ewidget != combo_box->priv->button)
+        {
+          gtk_combo_box_list_remove_grabs (combo_box);
+          gtk_combo_box_popdown (combo_box);
+
+          return TRUE;
+        }
+
+      return FALSE;
+    }
+
+  /* drop grabs */
+  gtk_combo_box_list_remove_grabs (combo_box);
+
+  /* select something cool */
+  ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+                                       event->x, event->y,
+                                       &path,
+                                       NULL, NULL, NULL);
+
+  if (!ret)
+    return TRUE; /* clicked outside window? */
+
+  gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
+  gtk_combo_box_popdown (combo_box);
+
+  gtk_tree_path_free (path);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_combo_box_list_key_press (GtkWidget   *widget,
+                              GdkEventKey *event,
+                              gpointer     data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+
+  if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
+       event->keyval == GDK_space || event->keyval == GDK_KP_Space) ||
+      event->keyval == GDK_Escape)
+    {
+      if (event->keyval != GDK_Escape)
+        {
+          gboolean ret;
+          GtkTreeIter iter;
+          GtkTreeModel *model = NULL;
+          GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
+
+          ret = gtk_tree_selection_get_selected (sel, &model, &iter);
+          if (ret)
+            {
+              GtkTreePath *path;
+
+              path = gtk_tree_model_get_path (model, &iter);
+              if (path)
+                {
+                  gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
+                  gtk_tree_path_free (path);
+                }
+            }
+        }
+      else
+        /* reset active item -- this is incredibly lame and ugly */
+        gtk_combo_box_set_active (combo_box,
+                                  gtk_combo_box_get_active (combo_box));
+
+      gtk_combo_box_list_remove_grabs (combo_box);
+      gtk_combo_box_popdown (combo_box);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_combo_box_list_row_changed (GtkTreeModel *model,
+                                GtkTreePath  *path,
+                                GtkTreeIter  *iter,
+                                gpointer      data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
+  gint width;
+
+  width = gtk_combo_box_calc_requested_width (combo_box, path);
+
+  if (width > combo_box->priv->width)
+    {
+      gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
+      gtk_widget_queue_resize (combo_box->priv->cell_view);
+      combo_box->priv->width = width;
+    }
+}
+
+/*
+ * public API
+ */
+
+GtkWidget *
+gtk_combo_box_new (GtkTreeModel *model)
+{
+  GtkComboBox *combo_box;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
+
+  combo_box = GTK_COMBO_BOX (g_object_new (gtk_combo_box_get_type (),
+                                           "model", model,
+                                           NULL));
+
+  return GTK_WIDGET (combo_box);
+}
+
+void
+gtk_combo_box_pack_start (GtkComboBox     *combo_box,
+                          GtkCellRenderer *cell,
+                          gboolean         expand)
+{
+  ComboCellInfo *info;
+  GtkWidget *menu;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+  info = g_new0 (ComboCellInfo, 1);
+  info->cell = cell;
+  info->expand = expand;
+  info->pack = GTK_PACK_START;
+
+  combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
+
+  if (combo_box->priv->cell_view)
+    gtk_cell_view_pack_start (GTK_CELL_VIEW (combo_box->priv->cell_view),
+                              cell, expand);
+
+  gtk_cell_view_pack_start (GTK_CELL_VIEW (combo_box->priv->measurer),
+                            cell, expand);
+
+  if (combo_box->priv->column)
+    gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
+
+  menu = combo_box->priv->popup_widget;
+  if (GTK_IS_MENU (menu))
+    {
+      GList *i, *list;
+
+      list = gtk_container_get_children (GTK_CONTAINER (menu));
+      for (i = list; i; i = i->next)
+        {
+          GtkCellView *view;
+
+          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
+            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
+          else
+            view = GTK_CELL_VIEW (i->data);
+
+          gtk_cell_view_pack_start (view, cell, expand);
+        }
+      g_list_free (list);
+    }
+}
+
+void
+gtk_combo_box_pack_end (GtkComboBox     *combo_box,
+                        GtkCellRenderer *cell,
+                        gboolean         expand)
+{
+  ComboCellInfo *info;
+  GtkWidget *menu;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+  info = g_new0 (ComboCellInfo, 1);
+  info->cell = cell;
+  info->expand = expand;
+  info->pack = GTK_PACK_END;
+
+  if (combo_box->priv->cell_view)
+    gtk_cell_view_pack_end (GTK_CELL_VIEW (combo_box->priv->cell_view),
+                            cell, expand);
+
+  gtk_cell_view_pack_end (GTK_CELL_VIEW (combo_box->priv->measurer),
+                          cell, expand);
+
+  if (combo_box->priv->column)
+    gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
+
+  menu = combo_box->priv->popup_widget;
+  if (GTK_IS_MENU (menu))
+    {
+      GList *i, *list;
+
+      list = gtk_container_get_children (GTK_CONTAINER (menu));
+      for (i = list; i; i = i->next)
+        {
+          GtkCellView *view;
+
+          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
+            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
+          else
+            view = GTK_CELL_VIEW (i->data);
+
+          gtk_cell_view_pack_end (view, cell, expand);
+        }
+      g_list_free (list);
+    }
+}
+
+void
+gtk_combo_box_set_attributes (GtkComboBox     *combo_box,
+                              GtkCellRenderer *cell,
+                              ...)
+{
+  va_list args;
+  gchar *attribute;
+  gint column;
+  gint attributes = 0;
+  ComboCellInfo *info;
+  GtkWidget *menu;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+  info = gtk_combo_box_get_cell_info (combo_box, cell);
+
+  va_start (args, cell);
+
+  attribute = va_arg (args, gchar *);
+
+  while (attribute)
+    {
+      column = va_arg (args, gint);
+
+      info->attributes = g_slist_prepend (info->attributes,
+                                          GINT_TO_POINTER (column));
+      info->attributes = g_slist_prepend (info->attributes,
+                                          g_strdup (attribute));
+
+      attributes++;
+
+      if (combo_box->priv->cell_view)
+        gtk_cell_view_add_attribute (GTK_CELL_VIEW (combo_box->priv->cell_view),
+                                     cell, attribute, column);
+
+      gtk_cell_view_add_attribute (GTK_CELL_VIEW (combo_box->priv->measurer),
+                                   cell, attribute, column);
+
+      if (combo_box->priv->column)
+        gtk_tree_view_column_add_attribute (combo_box->priv->column, cell,
+                                            attribute, column);
+
+      attribute = va_arg (args, gchar *);
+    }
+
+  va_end (args);
+
+  menu = combo_box->priv->popup_widget;
+  if (GTK_IS_MENU (menu))
+    {
+      GList *i, *list;
+
+      list = gtk_container_get_children (GTK_CONTAINER (menu));
+      for (i = list; i; i = i->next)
+        {
+          gint k;
+          GSList *j;
+          GtkCellView *view;
+
+          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
+            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
+          else
+            view = GTK_CELL_VIEW (i->data);
+
+          for (j = info->attributes, k = 0; k < attributes; k++)
+            {
+              gtk_cell_view_add_attribute (view, cell,
+                                           (gchar *)j->data,
+                                           GPOINTER_TO_INT (j->next->data));
+              j = j->next->next;
+            }
+        }
+      g_list_free (list);
+    }
+
+  gtk_combo_box_remeasure (combo_box);
+}
+
+void
+gtk_combo_box_clear (GtkComboBox *combo_box)
+{
+  GtkWidget *menu;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+
+  if (combo_box->priv->cell_view)
+    gtk_cell_view_clear (GTK_CELL_VIEW (combo_box->priv->cell_view));
+
+  if (combo_box->priv->measurer)
+    gtk_cell_view_clear (GTK_CELL_VIEW (combo_box->priv->measurer));
+
+  if (combo_box->priv->column)
+    gtk_tree_view_column_clear (combo_box->priv->column);
+
+  menu = combo_box->priv->popup_widget;
+  if (GTK_IS_MENU (menu))
+    {
+      GList *i, *list;
+
+      list = gtk_container_get_children (GTK_CONTAINER (menu));
+      for (i = list; i; i = i->next)
+        {
+          GtkCellView *view;
+
+          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
+            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
+          else
+            view = GTK_CELL_VIEW (i->data);
+
+          gtk_cell_view_clear (view);
+        }
+    }
+}
+
+void
+gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
+                              gint         width)
+{
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (width > 0);
+
+  combo_box->priv->wrap_width = width;
+
+  gtk_combo_box_relayout (combo_box);
+}
+
+void
+gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
+                                   gint         row_span)
+{
+  gint col;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+
+  col = gtk_tree_model_get_n_columns (combo_box->priv->model);
+  g_return_if_fail (row_span >= 0 && row_span < col);
+
+  combo_box->priv->row_column = row_span;
+
+  gtk_combo_box_relayout (combo_box);
+}
+
+void
+gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
+                                      gint         column_span)
+{
+  gint col;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+
+  col = gtk_tree_model_get_n_columns (combo_box->priv->model);
+  g_return_if_fail (column_span >= 0 && column_span < col);
+
+  combo_box->priv->col_column = column_span;
+
+  gtk_combo_box_relayout (combo_box);
+}
+
+gint
+gtk_combo_box_get_active (GtkComboBox *combo_box)
+{
+  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
+
+  return combo_box->priv->active_item;
+}
+
+void
+gtk_combo_box_set_active (GtkComboBox *combo_box,
+                          gint         index)
+{
+  GtkTreePath *path;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  /* -1 means "no item selected" */
+  g_return_if_fail (index >= -1);
+
+  if (combo_box->priv->active_item == index)
+    return;
+
+  combo_box->priv->active_item = index;
+
+  if (index == -1)
+    {
+      if (combo_box->priv->tree_view)
+        gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
+      else
+        {
+          GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
+
+          if (GTK_IS_MENU (menu))
+            gtk_menu_set_active (menu, -1);
+        }
+
+      if (combo_box->priv->cell_view)
+        gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
+    }
+  else
+    {
+      path = gtk_tree_path_new_from_indices (index, -1);
+
+      if (combo_box->priv->tree_view)
+        gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
+      else
+        {
+          GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
+
+          if (GTK_IS_MENU (menu))
+            gtk_menu_set_active (GTK_MENU (menu), index);
+        }
+
+      if (combo_box->priv->cell_view)
+        gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
+
+      gtk_tree_path_free (path);
+    }
+
+  g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
+}
+
+GtkTreeModel *
+gtk_combo_box_get_model (GtkComboBox *combo_box)
+{
+  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
+
+  return combo_box->priv->model;
+}
+
+
+GtkWidget *
+gtk_combo_box_new_text (void)
+{
+  GtkWidget *combo_box;
+  GtkCellRenderer *cell;
+  GtkListStore *store;
+
+  store = gtk_list_store_new (1, G_TYPE_STRING);
+
+  combo_box = gtk_combo_box_new (GTK_TREE_MODEL (store));
+
+  cell = gtk_cell_renderer_text_new ();
+  gtk_combo_box_pack_start (GTK_COMBO_BOX (combo_box),
+                            cell, TRUE);
+  gtk_combo_box_set_attributes (GTK_COMBO_BOX (combo_box),
+                                cell,
+                                "text", 0,
+                                NULL);
+
+  return combo_box;
+}
+
+void
+gtk_combo_box_append_text (GtkComboBox *combo_box,
+                           const gchar *text)
+{
+  GtkTreeIter iter;
+  GtkListStore *store;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
+  g_return_if_fail (text != NULL);
+
+  store = GTK_LIST_STORE (combo_box->priv->model);
+
+  gtk_list_store_append (store, &iter);
+  gtk_list_store_set (store, &iter, 0, text, -1);
+}
+
+void
+gtk_combo_box_insert_text (GtkComboBox *combo_box,
+                           gint         position,
+                           const gchar *text)
+{
+  GtkTreeIter iter;
+  GtkListStore *store;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
+  g_return_if_fail (position >= 0);
+  g_return_if_fail (text != NULL);
+
+  store = GTK_LIST_STORE (combo_box->priv->model);
+
+  gtk_list_store_insert (store, &iter, position);
+  gtk_list_store_set (store, &iter, 0, text, -1);
+}
+
+void
+gtk_combo_box_prepend_text (GtkComboBox *combo_box,
+                            const gchar *text)
+{
+  GtkTreeIter iter;
+  GtkListStore *store;
+
+  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
+  g_return_if_fail (text != NULL);
+
+  store = GTK_LIST_STORE (combo_box->priv->model);
+
+  gtk_list_store_prepend (store, &iter);
+  gtk_list_store_set (store, &iter, 0, text, -1);
+}
diff --git a/gtk/gtkcombobox.h b/gtk/gtkcombobox.h
new file mode 100644 (file)
index 0000000..b724f7a
--- /dev/null
@@ -0,0 +1,102 @@
+/* gtkcombobox.h
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COMBO_BOX_H__
+#define __GTK_COMBO_BOX_H__
+
+#include <gtk/gtkbin.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreeview.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COMBO_BOX             (gtk_combo_box_get_type ())
+#define GTK_COMBO_BOX(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COMBO_BOX, GtkComboBox))
+#define GTK_COMBO_BOX_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_COMBO_BOX, GtkComboBoxClass))
+#define GTK_IS_COMBO_BOX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COMBO_BOX))
+#define GTK_IS_COMBO_BOX_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_COMBO_BOX))
+#define GTK_COMBO_BOX_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_COMBO_BOX, GtkComboBoxClass))
+#define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))
+
+typedef struct _GtkComboBox        GtkComboBox;
+typedef struct _GtkComboBoxClass   GtkComboBoxClass;
+typedef struct _GtkComboBoxPrivate GtkComboBoxPrivate;
+
+struct _GtkComboBox
+{
+  GtkBin parent_instance;
+
+  /*< private >*/
+  GtkComboBoxPrivate *priv;
+};
+
+struct _GtkComboBoxClass
+{
+  GtkBinClass parent_class;
+
+  /* signals */
+  void     (* changed)          (GtkComboBox *combo_box);
+};
+
+
+/* construction */
+GType         gtk_combo_box_get_type         (void);
+GtkWidget    *gtk_combo_box_new              (GtkTreeModel    *model);
+
+/* manipulate list of cell renderers */
+void          gtk_combo_box_pack_start       (GtkComboBox     *combo_box,
+                                              GtkCellRenderer *cell,
+                                              gboolean         expand);
+void          gtk_combo_box_pack_end         (GtkComboBox     *combo_box,
+                                              GtkCellRenderer *cell,
+                                              gboolean         expand);
+void          gtk_combo_box_set_attributes   (GtkComboBox     *combo_box,
+                                              GtkCellRenderer *cell,
+                                              ...);
+void          gtk_combo_box_clear            (GtkComboBox     *combo_box);
+
+/* grids */
+void          gtk_combo_box_set_wrap_width         (GtkComboBox *combo_box,
+                                                    gint         width);
+void          gtk_combo_box_set_row_span_column    (GtkComboBox *combo_box,
+                                                    gint         row_span);
+void          gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
+                                                    gint         column_span);
+
+/* get/set active item */
+gint          gtk_combo_box_get_active       (GtkComboBox     *combo_box);
+void          gtk_combo_box_set_active       (GtkComboBox     *combo_box,
+                                              gint             index);
+
+/* getters and setters */
+GtkTreeModel *gtk_combo_box_get_model        (GtkComboBox     *combo_box);
+
+/* convenience -- text */
+GtkWidget    *gtk_combo_box_new_text         (void);
+void          gtk_combo_box_append_text      (GtkComboBox     *combo_box,
+                                              const gchar     *text);
+void          gtk_combo_box_insert_text      (GtkComboBox     *combo_box,
+                                              gint             position,
+                                              const gchar     *text);
+void          gtk_combo_box_prepend_text     (GtkComboBox     *combo_box,
+                                              const gchar     *text);
+
+G_END_DECLS
+
+#endif /* __GTK_COMBO_BOX_H__ */
diff --git a/gtk/gtkcomboboxentry.c b/gtk/gtkcomboboxentry.c
new file mode 100644 (file)
index 0000000..7d29916
--- /dev/null
@@ -0,0 +1,177 @@
+/* gtkcomboboxentry.c
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkcomboboxentry.h>
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkcellrenderertext.h>
+
+struct _GtkComboBoxEntryPrivate
+{
+  GtkWidget *entry;
+
+  gint text_column;
+};
+
+static void gtk_combo_box_entry_class_init       (GtkComboBoxEntryClass *klass);
+static void gtk_combo_box_entry_init             (GtkComboBoxEntry      *entry_box);
+
+static void gtk_combo_box_entry_active_changed   (GtkComboBox           *combo_box,
+                                                  gpointer               user_data);
+static void gtk_combo_box_entry_contents_changed (GtkEntry              *entry,
+                                                  gpointer               user_data);
+
+
+GType
+gtk_combo_box_entry_get_type (void)
+{
+  static GType combo_box_entry_type = 0;
+
+  if (!combo_box_entry_type)
+    {
+      static const GTypeInfo combo_box_entry_info =
+        {
+          sizeof (GtkComboBoxEntryClass),
+          NULL, /* base_init */
+          NULL, /* base_finalize */
+          (GClassInitFunc) gtk_combo_box_entry_class_init,
+          NULL, /* class_finalize */
+          NULL, /* class_data */
+          sizeof (GtkComboBoxEntry),
+          0,
+          (GInstanceInitFunc) gtk_combo_box_entry_init
+        };
+
+      combo_box_entry_type = g_type_register_static (GTK_TYPE_COMBO_BOX,
+                                                     "GtkComboBoxEntry",
+                                                     &combo_box_entry_info,
+                                                     0);
+    }
+
+  return combo_box_entry_type;
+}
+
+static void
+gtk_combo_box_entry_class_init (GtkComboBoxEntryClass *klass)
+{
+  g_type_class_add_private ((GObjectClass *) klass,
+                            sizeof (GtkComboBoxEntryPrivate));
+}
+
+static void
+gtk_combo_box_entry_init (GtkComboBoxEntry *entry_box)
+{
+  entry_box->priv = GTK_COMBO_BOX_ENTRY_GET_PRIVATE (entry_box);
+}
+
+static void
+gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
+                                    gpointer     user_data)
+{
+  gint index;
+  GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (combo_box);
+
+  index = gtk_combo_box_get_active (combo_box);
+
+  g_signal_handlers_block_by_func (entry_box->priv->entry,
+                                   gtk_combo_box_entry_contents_changed,
+                                   combo_box);
+
+  if (index < 0)
+    gtk_entry_set_text (GTK_ENTRY (entry_box->priv->entry), "");
+  else
+    {
+      gchar *str = NULL;
+      GtkTreeIter iter;
+      GtkTreeModel *model;
+
+      model = gtk_combo_box_get_model (combo_box);
+
+      gtk_tree_model_iter_nth_child (model, &iter, NULL, index);
+      gtk_tree_model_get (model, &iter,
+                          entry_box->priv->text_column, &str,
+                          -1);
+
+      gtk_entry_set_text (GTK_ENTRY (entry_box->priv->entry), str);
+
+      g_free (str);
+    }
+
+  g_signal_handlers_unblock_by_func (entry_box->priv->entry,
+                                     gtk_combo_box_entry_contents_changed,
+                                     combo_box);
+}
+
+static void
+gtk_combo_box_entry_contents_changed (GtkEntry *entry,
+                                      gpointer  user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  g_signal_handlers_block_by_func (combo_box,
+                                   gtk_combo_box_entry_active_changed,
+                                   NULL);
+  gtk_combo_box_set_active (combo_box, -1);
+  g_signal_handlers_unblock_by_func (combo_box,
+                                     gtk_combo_box_entry_active_changed,
+                                     NULL);
+}
+
+/* public API */
+GtkWidget *
+gtk_combo_box_entry_new (GtkTreeModel *model,
+                         gint          text_column)
+{
+  GtkWidget *ret;
+  GtkCellRenderer *renderer;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
+  g_return_val_if_fail (text_column >= 0, NULL);
+  g_return_val_if_fail (text_column < gtk_tree_model_get_n_columns (model), NULL);
+
+  ret = g_object_new (gtk_combo_box_entry_get_type (),
+                      "model", model,
+                      NULL);
+
+  GTK_COMBO_BOX_ENTRY (ret)->priv->entry = gtk_entry_new ();
+  gtk_container_add (GTK_CONTAINER (ret),
+                     GTK_COMBO_BOX_ENTRY (ret)->priv->entry);
+
+  GTK_COMBO_BOX_ENTRY (ret)->priv->text_column = text_column;
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_combo_box_pack_start (GTK_COMBO_BOX (ret), renderer, TRUE);
+  gtk_combo_box_set_attributes (GTK_COMBO_BOX (ret), renderer,
+                                "text", text_column,
+                                NULL);
+
+  g_signal_connect (GTK_COMBO_BOX_ENTRY (ret)->priv->entry, "changed",
+                    G_CALLBACK (gtk_combo_box_entry_contents_changed), ret);
+  g_signal_connect (ret, "changed",
+                    G_CALLBACK (gtk_combo_box_entry_active_changed), NULL);
+
+  return ret;
+}
+
+gint
+gtk_combo_box_entry_get_text_column (GtkComboBoxEntry *entry_box)
+{
+  g_return_val_if_fail (GTK_IS_COMBO_BOX_ENTRY (entry_box), 0);
+
+  return entry_box->priv->text_column;
+}
diff --git a/gtk/gtkcomboboxentry.h b/gtk/gtkcomboboxentry.h
new file mode 100644 (file)
index 0000000..8e4c0db
--- /dev/null
@@ -0,0 +1,63 @@
+/* gtkcomboboxentry.h
+ * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_COMBO_BOX_ENTRY_H__
+#define __GTK_COMBO_BOX_ENTRY_H__
+
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtktreemodel.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COMBO_BOX_ENTRY             (gtk_combo_box_entry_get_type ())
+#define GTK_COMBO_BOX_ENTRY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntry))
+#define GTK_COMBO_BOX_ENTRY_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryClass))
+#define GTK_IS_COMBO_BOX_ENTRY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COMBO_BOX_ENTRY))
+#define GTK_IS_COMBO_BOX_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_COMBO_BOX_ENTRY))
+#define GTK_COMBO_BOX_ENTRY_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryClass))
+#define GTK_COMBO_BOX_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryPrivate))
+
+typedef struct _GtkComboBoxEntry             GtkComboBoxEntry;
+typedef struct _GtkComboBoxEntryClass        GtkComboBoxEntryClass;
+typedef struct _GtkComboBoxEntryPrivate      GtkComboBoxEntryPrivate;
+
+struct _GtkComboBoxEntry
+{
+  GtkComboBox parent_instance;
+
+  /*< private >*/
+  GtkComboBoxEntryPrivate *priv;
+};
+
+struct _GtkComboBoxEntryClass
+{
+  GtkComboBoxClass parent_class;
+};
+
+
+GType       gtk_combo_box_entry_get_type        (void);
+GtkWidget  *gtk_combo_box_entry_new             (GtkTreeModel     *model,
+                                                 gint              text_column);
+
+gint        gtk_combo_box_entry_get_text_column (GtkComboBoxEntry *entry_box);
+
+
+G_END_DECLS
+
+#endif /* __GTK_COMBO_BOX_ENTRY_H__ */
index 367777581a289548a55751211f8118e41af2f511..a669fce39f5e3034a99e1db9f3ef2fe7fc4287ed 100644 (file)
@@ -29,6 +29,7 @@ endif
 noinst_PROGRAMS =                      \
        simple                          \
        testcalendar                    \
+       testcombo                       \
        testdnd                         \
        testgtk                         \
        testicontheme                   \
@@ -61,6 +62,7 @@ noinst_PROGRAMS =                     \
 simple_DEPENDENCIES = $(TEST_DEPS)
 testicontheme_DEPENDENCIES = $(TEST_DEPS)
 testcalendar_DEPENDENCIES = $(TEST_DEPS)
+testcombo_DEPENDENCIES = $(TEST_DEPS)
 testdnd_DEPENDENCIES = $(TEST_DEPS)
 testgtk_DEPENDENCIES = $(TEST_DEPS)
 testinput_DEPENDENCIES = $(TEST_DEPS)
@@ -86,6 +88,7 @@ testactions_DEPENDENCIES = $(TEST_DEPS)
 
 simple_LDADD = $(LDADDS)
 testcalendar_LDADD = $(LDADDS)
+testcombo_LDADD = $(LDADDS)
 testdnd_LDADD = $(LDADDS)
 testgtk_LDADD = $(LDADDS)
 testicontheme_LDADD = $(LDADDS)
diff --git a/tests/testcombo.c b/tests/testcombo.c
new file mode 100644 (file)
index 0000000..f3ff6f8
--- /dev/null
@@ -0,0 +1,313 @@
+#include <gtk/gtk.h>
+#include <gtk/gtkcellview.h>
+#include <gtk/gtkcellviewmenuitem.h>
+
+#include <string.h>
+#include <stdio.h>
+
+/**
+ * oh yes, this test app surely has a lot of ugly code
+ */
+
+/* grid combo demo */
+static GdkPixbuf *
+create_color_pixbuf (const char *color)
+{
+        GdkPixbuf *pixbuf;
+        GdkColor col;
+
+        int x;
+        int num;
+        int rowstride;
+        guchar *pixels, *p;
+
+        if (!gdk_color_parse (color, &col))
+                return NULL;
+
+        pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                 FALSE, 8,
+                                 16, 16);
+
+        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+        p = pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+        num = gdk_pixbuf_get_width (pixbuf) *
+                gdk_pixbuf_get_height (pixbuf);
+
+        for (x = 0; x < num; x++) {
+                p[0] = col.red / 65535 * 255;
+                p[1] = col.green / 65535 * 255;
+                p[2] = col.blue / 65535 * 255;
+                p += 3;
+        }
+
+        return pixbuf;
+}
+
+static GtkWidget *
+create_combo_box_grid_demo ()
+{
+        GtkWidget *combo;
+        GtkTreeIter iter;
+        GtkCellRenderer *cell = gtk_cell_renderer_pixbuf_new ();
+        GtkListStore *store;
+
+        store = gtk_list_store_new (1, GDK_TYPE_PIXBUF);
+
+        combo = gtk_combo_box_new (GTK_TREE_MODEL (store));
+        gtk_combo_box_pack_start (GTK_COMBO_BOX (combo),
+                                  cell, TRUE);
+        gtk_combo_box_set_attributes (GTK_COMBO_BOX (combo),
+                                      cell, "pixbuf", 0, NULL);
+        gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (combo),
+                                      3);
+
+        /* first row */
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("red"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("green"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("blue"),
+                            -1);
+
+        /* second row */
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("yellow"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("black"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("white"),
+                            -1);
+
+        /* third row */
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("gray"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("snow"),
+                            -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, create_color_pixbuf ("magenta"),
+                            -1);
+
+        gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+
+        return combo;
+}
+
+/* blaat */
+static GtkTreeModel *
+create_blaat ()
+{
+        GdkPixbuf *pixbuf;
+        GtkWidget *cellview;
+        GtkTreeIter iter;
+        GtkListStore *store;
+
+        cellview = gtk_cell_view_new ();
+
+        store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+
+        pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_DIALOG_WARNING,
+                                         GTK_ICON_SIZE_BUTTON, NULL);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, pixbuf,
+                            1, "gtk-stock-dialog-warning",
+                            -1);
+
+        pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_STOP,
+                                         GTK_ICON_SIZE_BUTTON, NULL);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, pixbuf,
+                            1, "gtk-stock-stop",
+                            -1);
+
+        pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_NEW,
+                                         GTK_ICON_SIZE_BUTTON, NULL);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, pixbuf,
+                            1, "gtk-stock-new",
+                            -1);
+
+        pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_CLEAR,
+                                         GTK_ICON_SIZE_BUTTON, NULL);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            0, pixbuf,
+                            1, "gtk-stock-clear",
+                            -1);
+
+        gtk_widget_destroy (cellview);
+
+        return GTK_TREE_MODEL (store);
+}
+
+static GtkTreeModel *
+create_text_store ()
+{
+        GtkTreeIter iter;
+        GtkListStore *store;
+
+        store = GTK_LIST_STORE (gtk_list_store_new (1, G_TYPE_STRING));
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "dum de dum", -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "la la la", -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "la la la dum de dum la la la la la la boom de da la la", -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "bloop", -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "bleep", -1);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, 0, "klaas", -1);
+
+        return GTK_TREE_MODEL (store);
+}
+
+int
+main (int argc, char **argv)
+{
+        GtkWidget *window, *cellview, *mainbox;
+        GtkWidget *combobox, *comboboxtext, *comboboxgrid;
+        GtkWidget *tmp, *boom;
+        GtkCellRenderer *renderer;
+        GdkPixbuf *pixbuf;
+        GValue value = {0, };
+
+        gtk_init (&argc, &argv);
+
+        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+        gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+        g_signal_connect (window, "delete_event", gtk_main_quit, NULL);
+
+        mainbox = gtk_vbox_new (FALSE, 2);
+        gtk_container_add (GTK_CONTAINER (window), mainbox);
+
+
+        /* GtkCellView */
+        tmp = gtk_frame_new ("GtkCellView");
+        gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
+
+        boom = gtk_vbox_new (FALSE, 0);
+        gtk_container_set_border_width (GTK_CONTAINER (boom), 5);
+        gtk_container_add (GTK_CONTAINER (tmp), boom);
+
+        cellview = gtk_cell_view_new ();
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_DIALOG_WARNING,
+                                         GTK_ICON_SIZE_BUTTON, NULL);
+
+        gtk_cell_view_pack_start (GTK_CELL_VIEW (cellview),
+                                  renderer,
+                                  FALSE);
+        g_value_init (&value, GDK_TYPE_PIXBUF);
+        g_value_set_instance (&value, pixbuf);
+        gtk_cell_view_set_values (GTK_CELL_VIEW (cellview),
+                                  renderer,
+                                  "pixbuf", &value,
+                                  NULL);
+        g_value_unset (&value);
+
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_cell_view_pack_start (GTK_CELL_VIEW (cellview),
+                                  renderer,
+                                  TRUE);
+        g_value_init (&value, G_TYPE_STRING);
+        g_value_set_string (&value, "la la la");
+        gtk_cell_view_set_values (GTK_CELL_VIEW (cellview),
+                                  renderer,
+                                  "text", &value,
+                                  NULL);
+        g_value_unset (&value);
+        gtk_container_add (GTK_CONTAINER (boom), cellview);
+
+
+        /* GtkComboBox */
+        tmp = gtk_frame_new ("GtkComboBox");
+        gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
+
+        boom = gtk_vbox_new (FALSE, 0);
+        gtk_container_set_border_width (GTK_CONTAINER (boom), 5);
+        gtk_container_add (GTK_CONTAINER (tmp), boom);
+
+        combobox = gtk_combo_box_new (create_blaat ());
+        gtk_container_add (GTK_CONTAINER (boom), combobox);
+
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        gtk_combo_box_pack_start (GTK_COMBO_BOX (combobox),
+                                  renderer,
+                                  FALSE);
+        gtk_combo_box_set_attributes (GTK_COMBO_BOX (combobox), renderer, "pixbuf", 0, NULL);
+
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_combo_box_pack_start (GTK_COMBO_BOX (combobox),
+                                  renderer,
+                                  TRUE);
+        gtk_combo_box_set_attributes (GTK_COMBO_BOX (combobox), renderer, "text", 1, NULL);
+
+        gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 1);
+
+
+        /* GtkComboBox (grid mode) */
+        tmp = gtk_frame_new ("GtkComboBox (grid mode)");
+        gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
+
+        boom = gtk_vbox_new (FALSE, 0);
+        gtk_container_set_border_width (GTK_CONTAINER (boom), 5);
+        gtk_container_add (GTK_CONTAINER (tmp), boom);
+
+        comboboxgrid = create_combo_box_grid_demo ();
+        gtk_box_pack_start (GTK_BOX (boom), comboboxgrid, FALSE, FALSE, 0);
+
+
+        /* GtkComboBoxEntry */
+        tmp = gtk_frame_new ("GtkComboBoxEntry");
+        gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
+
+        boom = gtk_vbox_new (FALSE, 0);
+        gtk_container_set_border_width (GTK_CONTAINER (boom), 5);
+        gtk_container_add (GTK_CONTAINER (tmp), boom);
+
+        comboboxtext = gtk_combo_box_entry_new (create_text_store (), 0);
+        gtk_container_add (GTK_CONTAINER (boom), comboboxtext);
+
+        /* done */
+        gtk_widget_show_all (window);
+
+        gtk_main ();
+
+        return 0;
+}
+
+/* vim:expandtab
+ */